コード例 #1
0
static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
{
	if (!scene->unit.system) {
		return fss->realsize;
	}
	else {
		float dim[3];
		float longest_axis;
		
		BKE_object_dimensions_get(domainob, dim);
		longest_axis = max_fff(dim[0], dim[1], dim[2]);
		
		return longest_axis * scene->unit.scale_length;
	}
}
コード例 #2
0
void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion)
{
	m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f);
	// smaller dispersion range for somewhat more control
	float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f);
	m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f);
	m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f);
	m_maxk = max_fff(m_k[0], m_k[1], m_k[2]);
	m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) :
	                                    (1.0f / (1.0f +        m_maxk));
	m_dk4[0] = 4.0f * (m_k[1] - m_k[0]);
	m_dk4[1] = 4.0f * (m_k[2] - m_k[1]);
	m_dk4[2] = 0.0f; /* unused */

	mul_v3_v3fl(m_k4, m_k, 4.0f);
}
コード例 #3
0
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	bool changed = true;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{
		if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
			ID *obdata = ob->data;
			if (ID_REAL_USERS(obdata) > 1) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}

			if (obdata->lib) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			Curve *cu;

			cu = ob->data;

			if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
				BKE_reportf(reports, RPT_ERROR,
				            "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
			if (cu->key) {
				BKE_reportf(reports, RPT_ERROR,
				            "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ob->type == OB_FONT) {
			if (apply_rot || apply_loc) {
				BKE_reportf(reports, RPT_ERROR,
				            "Font's can only have scale applied: \"%s\"",
				            ob->id.name + 2);
				changed = false;
			}
		}
	}
	CTX_DATA_END;
	
	if (!changed)
		return OPERATOR_CANCELLED;

	changed = false;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat, true);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				float tmat[3][3];
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;

			if (apply_scale)
				multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			BKE_mesh_transform(me, mat, true);
			
			/* update normals */
			BKE_mesh_calc_normals(me);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;

			BKE_lattice_transform(lt, mat, true);
		}
		else if (ob->type == OB_MBALL) {
			MetaBall *mb = ob->data;
			BKE_mball_transform(mb, mat);
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;
			scale = mat3_to_scale(rsmat);
			BKE_curve_transform_ex(cu, mat, true, scale);
		}
		else if (ob->type == OB_FONT) {
			Curve *cu = ob->data;
			int i;

			scale = mat3_to_scale(rsmat);

			for (i = 0; i < cu->totbox; i++) {
				TextBox *tb = &cu->tb[i];
				tb->x *= scale;
				tb->y *= scale;
				tb->w *= scale;
				tb->h *= scale;
			}

			cu->fsize *= scale;
		}
		else if (ob->type == OB_CAMERA) {
			MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);

			/* applying scale on camera actually scales clip's reconstruction.
			 * of there's clip assigned to camera nothing to do actually.
			 */
			if (!clip)
				continue;

			if (apply_scale)
				BKE_tracking_reconstruction_scale(&clip->tracking, ob->size);
		}
		else if (ob->type == OB_EMPTY) {
			/* It's possible for empties too, even though they don't 
			 * really have obdata, since we can simply apply the maximum
			 * scaling to the empty's drawsize.
			 *
			 * Core Assumptions:
			 * 1) Most scaled empties have uniform scaling 
			 *    (i.e. for visibility reasons), AND/OR
			 * 2) Preserving non-uniform scaling is not that important,
			 *    and is something that many users would be willing to
			 *    sacrifice for having an easy way to do this.
			 */

			if ((apply_loc == false) &&
			    (apply_rot == false) &&
			    (apply_scale == true))
			{
				float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2]));
				ob->empty_drawsize *= max_scale;
			}
		}
		else {
			continue;
		}

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		changed = true;
	}
	CTX_DATA_END;

	if (!changed) {
		BKE_report(reports, RPT_WARNING, "Objects have no data to transform");
		return OPERATOR_CANCELLED;
	}

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}
コード例 #4
0
ファイル: view3d_view.c プロジェクト: greg100795/blender-git
static bool view3d_localview_init(
        wmWindowManager *wm, wmWindow *win,
        Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx,
        ReportList *reports)
{
	View3D *v3d = sa->spacedata.first;
	Base *base;
	float min[3], max[3], box[3], mid[3];
	float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f;
	unsigned int locallay;
	bool ok = false;

	if (v3d->localvd) {
		return ok;
	}

	INIT_MINMAX(min, max);

	locallay = free_localbit(bmain);

	if (locallay == 0) {
		BKE_report(reports, RPT_ERROR, "No more than 8 local views");
		ok = false;
	}
	else {
		if (scene->obedit) {
			BKE_object_minmax(scene->obedit, min, max, false);
			
			ok = true;
		
			BASACT->lay |= locallay;
			scene->obedit->lay = BASACT->lay;
		}
		else {
			for (base = FIRSTBASE; base; base = base->next) {
				if (TESTBASE(v3d, base)) {
					BKE_object_minmax(base->object, min, max, false);
					base->lay |= locallay;
					base->object->lay = base->lay;
					ok = true;
				}
			}
		}

		sub_v3_v3v3(box, max, min);
		size = max_fff(box[0], box[1], box[2]);

		/* do not zoom closer than the near clipping plane */
		size = max_ff(size, v3d->near * 1.5f);

		/* perspective size (we always switch out of camera view so no need to use its lens size) */
		size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN;
		size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
	}
	
	if (ok == true) {
		ARegion *ar;
		
		v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
		
		memcpy(v3d->localvd, v3d, sizeof(View3D));

		mid_v3_v3v3(mid, min, max);

		copy_v3_v3(v3d->cursor, mid);

		for (ar = sa->regionbase.first; ar; ar = ar->next) {
			if (ar->regiontype == RGN_TYPE_WINDOW) {
				RegionView3D *rv3d = ar->regiondata;

				/* new view values */
				Object *camera_old = NULL;
				float dist_new, ofs_new[3];

				rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
				memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));

				negate_v3_v3(ofs_new, mid);

				if (rv3d->persp == RV3D_CAMOB) {
					rv3d->persp = RV3D_PERSP;
					camera_old = v3d->camera;
				}

				/* perspective should be a bit farther away to look nice */
				if (rv3d->persp != RV3D_ORTHO) {
					dist_new = size_persp;
				}
				else {
					dist_new = size_ortho;
				}

				/* correction for window aspect ratio */
				if (ar->winy > 2 && ar->winx > 2) {
					float asp = (float)ar->winx / (float)ar->winy;
					if (asp < 1.0f) asp = 1.0f / asp;
					dist_new *= asp;
				}

				ED_view3d_smooth_view_ex(
				        wm, win, sa,
				        v3d, ar, camera_old, NULL,
				        ofs_new, NULL, &dist_new, NULL,
				        smooth_viewtx);
			}
		}
		
		v3d->lay = locallay;
	}
	else {
		/* clear flags */ 
		for (base = FIRSTBASE; base; base = base->next) {
			if (base->lay & locallay) {
				base->lay -= locallay;
				if (base->lay == 0) base->lay = v3d->layact;
				if (base->object != scene->obedit) base->flag |= SELECT;
				base->object->lay = base->lay;
			}
		}
	}

	return ok;
}
コード例 #5
0
/* assumes *dst is type RGBA */
static void lensDistort(CompBuf *dst, CompBuf *src, float kr, float kg, float kb, int jit, int proj, int fit)
{
    int x, y, z;
    const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y;

    if (proj) {
        // shift
        CompBuf *tsrc = dupalloc_compbuf(src);

        for (z=0; z<tsrc->type; ++z)
            IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1);
        kr *= 20.f;

        for (y=0; y<dst->y; y++) {
            fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
            const float v = (y + 0.5f)/(float)dst->y;

            for (x=0; x<dst->x; x++) {
                const float u = (x + 0.5f)/(float)dst->x;

                qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]);
                if (tsrc->type == CB_VAL)
                    colp[x][1] = tsrc->rect[x + y*tsrc->x];
                else
                    colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1];
                qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2);

                /* set alpha */
                colp[x][3] = 1.0f;
            }
        }
        free_compbuf(tsrc);
    }
    else {
        // Spherical
        // Scale factor to make bottom/top & right/left sides fit in window after deform
        // so in the case of pincushion (kn < 0), corners will be outside window.
        // Now also optionally scales image such that black areas are not visible when distort factor is positive
        // (makes distorted corners match window corners, but really only valid if mk<=0.5)
        const float mk = max_fff(kr, kg, kb);
        const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk));
        const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg);

        kr *= 4.f, kg *= 4.f, kb *= 4.f;

        for (y=0; y<dst->y; y++) {
            fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
            const float v = sc*((y + 0.5f) - cy)/cy;

            for (x=0; x<dst->x; x++) {
                int dr = 0, dg = 0, db = 0;
                float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
                fRGB c1, tc = {0, 0, 0, 0};
                const float u = sc*((x + 0.5f) - cx)/cx;
                const float uv_dot = u * u + v * v;
                int sta = 0, mid = 0, end = 0;

                if ((t = 1.f - kr*uv_dot) >= 0.f) {
                    d = 1.f/(1.f + sqrtf(t));
                    ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f;
                    sta = 1;
                }
                if ((t = 1.f - kg*uv_dot) >= 0.f) {
                    d = 1.f/(1.f + sqrtf(t));
                    ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f;
                    mid = 1;
                }
                if ((t = 1.f - kb*uv_dot) >= 0.f) {
                    d = 1.f/(1.f + sqrtf(t));
                    ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f;
                    end = 1;
                }

                if (sta && mid && end) {
                    // RG
                    const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
                    const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
                    const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
                    const float sd = 1.f/(float)ds;

                    for (z=0; z<ds; ++z) {
                        const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
                        t = 1.f - (kr + tz*drg)*uv_dot;
                        d = 1.f / (1.f + sqrtf(t));
                        qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
                        if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
                        tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1];
                        dr++, dg++;
                    }
                    // GB
                    {
                        const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
                        const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
                        const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
                        const float sd = 1.f/(float)ds;

                        for (z=0; z<ds; ++z) {
                            const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
                            t = 1.f - (kg + tz*dgb)*uv_dot;
                            d = 1.f / (1.f + sqrtf(t));
                            qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
                            if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
                            tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2];
                            dg++, db++;
                        }
                    }
                }

                if (dr) colp[x][0] = 2.f*tc[0] / (float)dr;
                if (dg) colp[x][1] = 2.f*tc[1] / (float)dg;
                if (db) colp[x][2] = 2.f*tc[2] / (float)db;

                /* set alpha */
                colp[x][3] = 1.0f;
            }
        }
    }
}
コード例 #6
0
ファイル: view3d_view.c プロジェクト: pawkoz/dyplom
static bool view3d_localview_init(
        wmWindowManager *wm, wmWindow *win,
        Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx,
        ReportList *reports)
{
	View3D *v3d = sa->spacedata.first;
	Base *base;
	float min[3], max[3], box[3], mid[3];
	float size = 0.0f;
	unsigned int locallay;
	bool ok = false;

	if (v3d->localvd) {
		return ok;
	}

	INIT_MINMAX(min, max);

	locallay = free_localbit(bmain);

	if (locallay == 0) {
		BKE_report(reports, RPT_ERROR, "No more than 8 local views");
		ok = false;
	}
	else {
		if (scene->obedit) {
			BKE_object_minmax(scene->obedit, min, max, false);
			
			ok = true;
		
			BASACT->lay |= locallay;
			scene->obedit->lay = BASACT->lay;
		}
		else {
			for (base = FIRSTBASE; base; base = base->next) {
				if (TESTBASE(v3d, base)) {
					BKE_object_minmax(base->object, min, max, false);
					base->lay |= locallay;
					base->object->lay = base->lay;
					ok = true;
				}
			}
		}

		sub_v3_v3v3(box, max, min);
		size = max_fff(box[0], box[1], box[2]);
	}
	
	if (ok == true) {
		ARegion *ar;
		
		v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
		
		memcpy(v3d->localvd, v3d, sizeof(View3D));

		mid_v3_v3v3(mid, min, max);

		copy_v3_v3(v3d->cursor, mid);

		for (ar = sa->regionbase.first; ar; ar = ar->next) {
			if (ar->regiontype == RGN_TYPE_WINDOW) {
				RegionView3D *rv3d = ar->regiondata;
				bool ok_dist = true;

				/* new view values */
				Object *camera_old = NULL;
				float dist_new, ofs_new[3];

				rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
				memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));

				negate_v3_v3(ofs_new, mid);

				if (rv3d->persp == RV3D_CAMOB) {
					rv3d->persp = RV3D_PERSP;
					camera_old = v3d->camera;
				}

				if (rv3d->persp == RV3D_ORTHO) {
					if (size < 0.0001f) {
						ok_dist = false;
					}
				}

				if (ok_dist) {
					dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
					if (rv3d->persp == RV3D_PERSP) {
						/* don't zoom closer than the near clipping plane */
						dist_new = max_ff(dist_new, v3d->near * 1.5f);
					}
				}

				ED_view3d_smooth_view_ex(
				        wm, win, sa,
				        v3d, ar, camera_old, NULL,
				        ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
				        smooth_viewtx);
			}
		}
		
		v3d->lay = locallay;
	}
	else {
		/* clear flags */ 
		for (base = FIRSTBASE; base; base = base->next) {
			if (base->lay & locallay) {
				base->lay -= locallay;
				if (base->lay == 0) base->lay = v3d->layact;
				if (base->object != scene->obedit) base->flag |= SELECT;
				base->object->lay = base->lay;
			}
		}
	}

	return ok;
}
コード例 #7
0
ファイル: drawvolume.c プロジェクト: Eibriel/kiriblender
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                       GPUTexture *tex, float min[3], float max[3],
                       int res[3], float dx, float UNUSED(base_scale), float viewnormal[3],
                       GPUTexture *tex_shadow, GPUTexture *tex_flame)
{
	int i, j, k, n, good_index;
	float d /*, d0 */ /* UNUSED */, dd, ds;
	float *points = NULL;
	int numpoints = 0;
	float cor[3] = {1.0f, 1.0f, 1.0f};
	int gl_depth = 0, gl_blend = 0;

	/* draw slices of smoke is adapted from c++ code authored
	 * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */
	float cv[][3] = {
		{1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
		{1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
	};

	/* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
	float edges[12][2][3] = {
		{{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},

		{{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},

		{{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
	};

	unsigned char *spec_data;
	float *spec_pixels;
	GPUTexture *tex_spec;

	/* Fragment program to calculate the view3d of smoke */
	/* using 4 textures, density, shadow, flame and flame spectrum */
	const char *shader_basic =
	        "!!ARBfp1.0\n"
	        "PARAM dx = program.local[0];\n"
	        "PARAM darkness = program.local[1];\n"
	        "PARAM render = program.local[2];\n"
	        "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
	        "TEMP temp, shadow, flame, spec, value;\n"
	        "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
	        "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
	        "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
	        "TEX spec, flame.r, texture[3], 1D;\n"
	        /* calculate shading factor from density */
	        "MUL value.r, temp.a, darkness.a;\n"
	        "MUL value.r, value.r, dx.r;\n"
	        "MUL value.r, value.r, f.r;\n"
	        "EX2 temp, -value.r;\n"
	        /* alpha */
	        "SUB temp.a, 1.0, temp.r;\n"
	        /* shade colors */
	        "MUL temp.r, temp.r, shadow.r;\n"
	        "MUL temp.g, temp.g, shadow.r;\n"
	        "MUL temp.b, temp.b, shadow.r;\n"
	        "MUL temp.r, temp.r, darkness.r;\n"
	        "MUL temp.g, temp.g, darkness.g;\n"
	        "MUL temp.b, temp.b, darkness.b;\n"
	        /* for now this just replace smoke shading if rendering fire */
	        "CMP result.color, render.r, temp, spec;\n"
	        "END\n";

	/* color shader */
	const char *shader_color =
	        "!!ARBfp1.0\n"
	        "PARAM dx = program.local[0];\n"
	        "PARAM darkness = program.local[1];\n"
	        "PARAM render = program.local[2];\n"
	        "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
	        "TEMP temp, shadow, flame, spec, value;\n"
	        "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
	        "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
	        "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
	        "TEX spec, flame.r, texture[3], 1D;\n"
	        /* unpremultiply volume texture */
	        "RCP value.r, temp.a;\n"
	        "MUL temp.r, temp.r, value.r;\n"
	        "MUL temp.g, temp.g, value.r;\n"
	        "MUL temp.b, temp.b, value.r;\n"
	        /* calculate shading factor from density */
	        "MUL value.r, temp.a, darkness.a;\n"
	        "MUL value.r, value.r, dx.r;\n"
	        "MUL value.r, value.r, f.r;\n"
	        "EX2 value.r, -value.r;\n"
	        /* alpha */
	        "SUB temp.a, 1.0, value.r;\n"
	        /* shade colors */
	        "MUL temp.r, temp.r, shadow.r;\n"
	        "MUL temp.g, temp.g, shadow.r;\n"
	        "MUL temp.b, temp.b, shadow.r;\n"
	        "MUL temp.r, temp.r, value.r;\n"
	        "MUL temp.g, temp.g, value.r;\n"
	        "MUL temp.b, temp.b, value.r;\n"
	        /* for now this just replace smoke shading if rendering fire */
	        "CMP result.color, render.r, temp, spec;\n"
	        "END\n";

	GLuint prog;

	
	float size[3];

	if (!tex) {
		printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
		return;
	}

#ifdef DEBUG_DRAW_TIME
	TIMEIT_START(draw);
#endif

	/* generate flame spectrum texture */
	#define SPEC_WIDTH 256
	#define FIRE_THRESH 7
	#define MAX_FIRE_ALPHA 0.06f
	#define FULL_ON_FIRE 100
	spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char));
	flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
	spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float));
	for (i = 0; i < 16; i++) {
		for (j = 0; j < 16; j++) {
			for (k = 0; k < SPEC_WIDTH; k++) {
				int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
				if (k >= FIRE_THRESH) {
					spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f;
					spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f;
					spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f;
					spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
					        (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
				}
				else {
					spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f;
				}
			}
		}
	}

	tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);

	sub_v3_v3v3(size, max, min);

	/* maxx, maxy, maxz */
	cv[0][0] = max[0];
	cv[0][1] = max[1];
	cv[0][2] = max[2];
	/* minx, maxy, maxz */
	cv[1][0] = min[0];
	cv[1][1] = max[1];
	cv[1][2] = max[2];
	/* minx, miny, maxz */
	cv[2][0] = min[0];
	cv[2][1] = min[1];
	cv[2][2] = max[2];
	/* maxx, miny, maxz */
	cv[3][0] = max[0];
	cv[3][1] = min[1];
	cv[3][2] = max[2];

	/* maxx, maxy, minz */
	cv[4][0] = max[0];
	cv[4][1] = max[1];
	cv[4][2] = min[2];
	/* minx, maxy, minz */
	cv[5][0] = min[0];
	cv[5][1] = max[1];
	cv[5][2] = min[2];
	/* minx, miny, minz */
	cv[6][0] = min[0];
	cv[6][1] = min[1];
	cv[6][2] = min[2];
	/* maxx, miny, minz */
	cv[7][0] = max[0];
	cv[7][1] = min[1];
	cv[7][2] = min[2];

	copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */
	copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */
	copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */
	copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */
	copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */

	// printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
	// printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);

	edges[0][1][2] = size[2];
	edges[1][1][2] = size[2];
	edges[2][1][2] = size[2];
	edges[3][1][2] = size[2];

	edges[4][1][1] = size[1];
	edges[5][1][1] = size[1];
	edges[6][1][1] = size[1];
	edges[7][1][1] = size[1];

	edges[8][1][0] = size[0];
	edges[9][1][0] = size[0];
	edges[10][1][0] = size[0];
	edges[11][1][0] = size[0];

	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);

	glDepthMask(GL_FALSE);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);

	/* find cube vertex that is closest to the viewer */
	for (i = 0; i < 8; i++) {
		float x, y, z;

		x = cv[i][0] - viewnormal[0] * size[0] * 0.5f;
		y = cv[i][1] - viewnormal[1] * size[1] * 0.5f;
		z = cv[i][2] - viewnormal[2] * size[2] * 0.5f;

		if ((x >= min[0]) && (x <= max[0]) &&
		    (y >= min[1]) && (y <= max[1]) &&
		    (z >= min[2]) && (z <= max[2]))
		{
			break;
		}
	}

	if (i >= 8) {
		/* fallback, avoid using buffer over-run */
		i = 0;
	}

	// printf("i: %d\n", i);
	// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);

	if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
		glEnable(GL_FRAGMENT_PROGRAM_ARB);
		glGenProgramsARB(1, &prog);

		glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
		/* set shader */
		if (sds->active_fields & SM_ACTIVE_COLORS)
			glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
		else
			glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);

		/* cell spacing */
		glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
		/* custom parameter for smoke style (higher = thicker) */
		if (sds->active_fields & SM_ACTIVE_COLORS)
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
		else
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
	}
	else
		printf("Your gfx card does not support 3D View smoke drawing.\n");

	GPU_texture_bind(tex, 0);
	if (tex_shadow)
		GPU_texture_bind(tex_shadow, 1);
	else
		printf("No volume shadow\n");

	if (tex_flame) {
		GPU_texture_bind(tex_flame, 2);
		GPU_texture_bind(tex_spec, 3);
	}

	if (!GPU_non_power_of_two_support()) {
		cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]);
		cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]);
		cor[2] = (float)res[2] / (float)power_of_2_max_i(res[2]);
	}

	/* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
	 * (a,b,c), the plane normal, are given by viewdir
	 * d is the parameter along the view direction. the first d is given by
	 * inserting previously found vertex into the plane equation */

	/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
	ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
	dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
	n = 0;
	good_index = i;

	// printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);

	points = MEM_callocN(sizeof(float) * 12 * 3, "smoke_points_preview");

	while (1) {
		float p0[3];
		float tmp_point[3], tmp_point2[3];

		if (dd * (float)n > ds)
			break;

		copy_v3_v3(tmp_point, viewnormal);
		mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n));
		add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
		d = dot_v3v3(tmp_point2, viewnormal);

		// printf("my d: %f\n", d);

		/* intersect_edges returns the intersection points of all cube edges with
		 * the given plane that lie within the cube */
		numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);

		// printf("points: %d\n", numpoints);

		if (numpoints > 2) {
			copy_v3_v3(p0, points);

			/* sort points to get a convex polygon */
			for (i = 1; i < numpoints - 1; i++) {
				for (j = i + 1; j < numpoints; j++) {
					if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) {
						float tmp2[3];
						copy_v3_v3(tmp2, &points[j * 3]);
						copy_v3_v3(&points[j * 3], &points[i * 3]);
						copy_v3_v3(&points[i * 3], tmp2);
					}
				}
			}

			/* render fire slice */
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
				             (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
				             (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
				glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
				           points[i * 3 + 1] / fabsf(ob->size[1]),
				           points[i * 3 + 2] / fabsf(ob->size[2]));
			}
			glEnd();

			/* render smoke slice */
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
				             (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
				             (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
				glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
				           points[i * 3 + 1] / fabsf(ob->size[1]),
				           points[i * 3 + 2] / fabsf(ob->size[2]));
			}
			glEnd();
		}
		n++;
	}

#ifdef DEBUG_DRAW_TIME
	printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
	TIMEIT_END(draw);
#endif

	if (tex_shadow)
		GPU_texture_unbind(tex_shadow);
	GPU_texture_unbind(tex);
	if (tex_flame) {
		GPU_texture_unbind(tex_flame);
		GPU_texture_unbind(tex_spec);
	}
	GPU_texture_free(tex_spec);

	free(spec_data);
	free(spec_pixels);

	if (GLEW_ARB_fragment_program) {
		glDisable(GL_FRAGMENT_PROGRAM_ARB);
		glDeleteProgramsARB(1, &prog);
	}


	MEM_freeN(points);

	if (!gl_blend) {
		glDisable(GL_BLEND);
	}

	if (gl_depth) {
		glEnable(GL_DEPTH_TEST);
		glDepthMask(GL_TRUE);
	}
}
コード例 #8
0
ファイル: imagetexture.c プロジェクト: wisaac407/blender
static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	TexResult texr;
	float fx, fy, minx, maxx, miny, maxy;
	float maxd, val1, val2, val3;
	int curmap, retval, intpol, extflag = 0;
	afdata_t AFD;

	void (*filterfunc)(TexResult*, ImBuf*, float, float, afdata_t*);
	switch (tex->texfilter) {
		case TXF_EWA:
			filterfunc = ewa_eval;
			break;
		case TXF_FELINE:
			filterfunc = feline_eval;
			break;
		case TXF_AREA:
		default:
			filterfunc = area_sample;
	}

	texres->tin = texres->ta = texres->tr = texres->tg = texres->tb = 0.f;

	/* we need to set retval OK, otherwise texture code generates normals itself... */
	retval = texres->nor ? 3 : 1;

	/* quick tests */
	if (ibuf==NULL && ima==NULL) return retval;

	if (ima) {	/* hack for icon render */
		if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
			return retval;
		}
		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
	}

	if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}

	if (ima) {
		ima->flag |= IMA_USED_FOR_RENDER;
	}

	/* mipmap test */
	image_mipmap_test(tex, ibuf);
	
	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((tex->imaflag & TEX_CALCALPHA) == 0) {
				texres->talpha = 1;
			}
		}
	}
	texr.talpha = texres->talpha;

	if (tex->imaflag & TEX_IMAROT) {
		fy = texvec[0];
		fx = texvec[1];
	}
	else {
		fx = texvec[0];
		fy = texvec[1];
	}

	if (ibuf->flags & IB_fields) {
		if (R.r.mode & R_FIELDS) {			/* field render */
			if (R.flag & R_SEC_FIELD) {		/* correction for 2nd field */
				/* fac1= 0.5/( (float)ibuf->y ); */
				/* fy-= fac1; */
			}
			else 	/* first field */
				fy += 0.5f/( (float)ibuf->y );
		}
	}

	/* pixel coordinates */
	minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
	maxy = max_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);

	/* tex_sharper has been removed */
	minx = (maxx - minx)*0.5f;
	miny = (maxy - miny)*0.5f;

	if (tex->imaflag & TEX_FILTER_MIN) {
		/* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
		const float addval = (0.5f * tex->filtersize) / (float)MIN2(ibuf->x, ibuf->y);
		if (addval > minx) minx = addval;
		if (addval > miny) miny = addval;
	}
	else if (tex->filtersize != 1.f) {
		minx *= tex->filtersize;
		miny *= tex->filtersize;
		dxt[0] *= tex->filtersize;
		dxt[1] *= tex->filtersize;
		dyt[0] *= tex->filtersize;
		dyt[1] *= tex->filtersize;
	}

	if (tex->imaflag & TEX_IMAROT) {
		float t;
		SWAP(float, minx, miny);
		/* must rotate dxt/dyt 90 deg
		 * yet another blender problem is that swapping X/Y axes (or any tex proj switches) should do something similar,
		 * but it doesn't, it only swaps coords, so filter area will be incorrect in those cases. */
		t = dxt[0];
		dxt[0] = dxt[1];
		dxt[1] = -t;
		t = dyt[0];
		dyt[0] = dyt[1];
		dyt[1] = -t;
	}

	/* side faces of unit-cube */
	minx = (minx > 0.25f) ? 0.25f : ((minx < 1e-5f) ? 1e-5f : minx);
	miny = (miny > 0.25f) ? 0.25f : ((miny < 1e-5f) ? 1e-5f : miny);

	/* repeat and clip */

	if (tex->extend == TEX_REPEAT) {
		if ((tex->flag & (TEX_REPEAT_XMIR | TEX_REPEAT_YMIR)) == (TEX_REPEAT_XMIR | TEX_REPEAT_YMIR))
			extflag = TXC_EXTD;
		else if (tex->flag & TEX_REPEAT_XMIR)
			extflag = TXC_XMIR;
		else if (tex->flag & TEX_REPEAT_YMIR)
			extflag = TXC_YMIR;
		else
			extflag = TXC_REPT;
	}
	else if (tex->extend == TEX_EXTEND)
		extflag = TXC_EXTD;

	if (tex->extend == TEX_CHECKER) {
		int xs = (int)floorf(fx), ys = (int)floorf(fy);
		/* both checkers available, no boundary exceptions, checkerdist will eat aliasing */
		if ((tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN)) {
			fx -= xs;
			fy -= ys;
		}
		else if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
		         (tex->flag & TEX_CHECKER_EVEN) == 0)
		{
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
		else {
			int xs1 = (int)floorf(fx - minx);
			int ys1 = (int)floorf(fy - miny);
			int xs2 = (int)floorf(fx + minx);
			int ys2 = (int)floorf(fy + miny);
			if ((xs1 != xs2) || (ys1 != ys2)) {
				if (tex->flag & TEX_CHECKER_ODD) {
					fx -= ((xs1 + ys) & 1) ? xs2 : xs1;
					fy -= ((ys1 + xs) & 1) ? ys2 : ys1;
				}
				if (tex->flag & TEX_CHECKER_EVEN) {
					fx -= ((xs1 + ys) & 1) ? xs1 : xs2;
					fy -= ((ys1 + xs) & 1) ? ys1 : ys2;
				}
			}
			else {
				if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) {
					if (ima)
						BKE_image_pool_release_ibuf(ima, ibuf, pool);
					return retval;
				}
				if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) {
					if (ima)
						BKE_image_pool_release_ibuf(ima, ibuf, pool);
					return retval;
				}
				fx -= xs;
				fy -= ys;
			}
		}
		/* scale around center, (0.5, 0.5) */
		if (tex->checkerdist < 1.f) {
			const float omcd = 1.f / (1.f - tex->checkerdist);
			fx = (fx - 0.5f)*omcd + 0.5f;
			fy = (fy - 0.5f)*omcd + 0.5f;
			minx *= omcd;
			miny *= omcd;
		}
	}

	if (tex->extend == TEX_CLIPCUBE) {
		if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f || texvec[2] < -1.f || texvec[2] > 1.f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else if (tex->extend == TEX_CLIP || tex->extend == TEX_CHECKER) {
		if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else {
		if (tex->extend == TEX_EXTEND) {
			fx = (fx > 1.f) ? 1.f : ((fx < 0.f) ? 0.f : fx);
			fy = (fy > 1.f) ? 1.f : ((fy < 0.f) ? 0.f : fy);
		}
		else {
			fx -= floorf(fx);
			fy -= floorf(fy);
		}
	}

	intpol = tex->imaflag & TEX_INTERPOL;

	/* warning no return! */
	if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
		ibuf->rect += ibuf->x*ibuf->y;

	/* struct common data */
	copy_v2_v2(AFD.dxt, dxt);
	copy_v2_v2(AFD.dyt, dyt);
	AFD.intpol = intpol;
	AFD.extflag = extflag;

	/* brecht: added stupid clamping here, large dx/dy can give very large
	 * filter sizes which take ages to render, it may be better to do this
	 * more intelligently later in the code .. probably it's not noticeable */
	if (AFD.dxt[0]*AFD.dxt[0] + AFD.dxt[1]*AFD.dxt[1] > 2.0f*2.0f)
		mul_v2_fl(AFD.dxt, 2.0f/len_v2(AFD.dxt));
	if (AFD.dyt[0]*AFD.dyt[0] + AFD.dyt[1]*AFD.dyt[1] > 2.0f*2.0f)
		mul_v2_fl(AFD.dyt, 2.0f/len_v2(AFD.dyt));

	/* choice: */
	if (tex->imaflag & TEX_MIPMAP) {
		ImBuf *previbuf, *curibuf;
		float levf;
		int maxlev;
		ImBuf *mipmaps[IMB_MIPMAP_LEVELS + 1];

		/* modify ellipse minor axis if too eccentric, use for area sampling as well
		 * scaling dxt/dyt as done in pbrt is not the same
		 * (as in ewa_eval(), scale by sqrt(ibuf->x) to maximize precision) */
		const float ff = sqrtf(ibuf->x), q = ibuf->y/ff;
		const float Ux = dxt[0]*ff, Vx = dxt[1]*q, Uy = dyt[0]*ff, Vy = dyt[1]*q;
		const float A = Vx*Vx + Vy*Vy;
		const float B = -2.f*(Ux*Vx + Uy*Vy);
		const float C = Ux*Ux + Uy*Uy;
		const float F = A*C - B*B*0.25f;
		float a, b, th, ecc;
		BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
		if (tex->texfilter == TXF_FELINE) {
			float fProbes;
			a *= ff;
			b *= ff;
			a = max_ff(a, 1.0f);
			b = max_ff(b, 1.0f);
			fProbes = 2.f*(a / b) - 1.f;
			AFD.iProbes = round_fl_to_int(fProbes);
			AFD.iProbes = MIN2(AFD.iProbes, tex->afmax);
			if (AFD.iProbes < fProbes)
				b = 2.f*a / (float)(AFD.iProbes + 1);
			AFD.majrad = a/ff;
			AFD.minrad = b/ff;
			AFD.theta = th;
			AFD.dusc = 1.f/ff;
			AFD.dvsc = ff / (float)ibuf->y;
		}
		else {	/* EWA & area */
			if (ecc > (float)tex->afmax) b = a / (float)tex->afmax;
			b *= ff;
		}
		maxd = max_ff(b, 1e-8f);
		levf = ((float)M_LOG2E) * logf(maxd);

		curmap = 0;
		maxlev = 1;
		mipmaps[0] = ibuf;
		while (curmap < IMB_MIPMAP_LEVELS) {
			mipmaps[curmap + 1] = ibuf->mipmap[curmap];
			if (ibuf->mipmap[curmap]) maxlev++;
			curmap++;
		}

		/* mipmap level */
		if (levf < 0.f) {  /* original image only */
			previbuf = curibuf = mipmaps[0];
			levf = 0.f;
		}
		else if (levf >= maxlev - 1) {
			previbuf = curibuf = mipmaps[maxlev - 1];
			levf = 0.f;
			if (tex->texfilter == TXF_FELINE) AFD.iProbes = 1;
		}
		else {
			const int lev = isnan(levf) ? 0 : (int)levf;
			curibuf = mipmaps[lev];
			previbuf = mipmaps[lev + 1];
			levf -= floorf(levf);
		}

		/* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */

		if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
			/* color & normal */
			filterfunc(texres, curibuf, fx, fy, &AFD);
			val1 = texres->tr + texres->tg + texres->tb;
			filterfunc(&texr, curibuf, fx + dxt[0], fy + dxt[1], &AFD);
			val2 = texr.tr + texr.tg + texr.tb;
			filterfunc(&texr, curibuf, fx + dyt[0], fy + dyt[1], &AFD);
			val3 = texr.tr + texr.tg + texr.tb;
			/* don't switch x or y! */
			texres->nor[0] = val1 - val2;
			texres->nor[1] = val1 - val3;
			if (previbuf != curibuf) {  /* interpolate */
				filterfunc(&texr, previbuf, fx, fy, &AFD);
				/* rgb */
				texres->tr += levf*(texr.tr - texres->tr);
				texres->tg += levf*(texr.tg - texres->tg);
				texres->tb += levf*(texr.tb - texres->tb);
				texres->ta += levf*(texr.ta - texres->ta);
				/* normal */
				val1 += levf*((texr.tr + texr.tg + texr.tb) - val1);
				filterfunc(&texr, previbuf, fx + dxt[0], fy + dxt[1], &AFD);
				val2 += levf*((texr.tr + texr.tg + texr.tb) - val2);
				filterfunc(&texr, previbuf, fx + dyt[0], fy + dyt[1], &AFD);
				val3 += levf*((texr.tr + texr.tg + texr.tb) - val3);
				texres->nor[0] = val1 - val2;  /* vals have been interpolated above! */
				texres->nor[1] = val1 - val3;
			}
		}
		else {  /* color */
			filterfunc(texres, curibuf, fx, fy, &AFD);
			if (previbuf != curibuf) {  /* interpolate */
				filterfunc(&texr, previbuf, fx, fy, &AFD);
				texres->tr += levf*(texr.tr - texres->tr);
				texres->tg += levf*(texr.tg - texres->tg);
				texres->tb += levf*(texr.tb - texres->tb);
				texres->ta += levf*(texr.ta - texres->ta);
			}

			if (tex->texfilter != TXF_EWA) {
				alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
			}
		}
	}
	else {	/* no mipmap */
		/* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */
		if (tex->texfilter == TXF_FELINE) {
			const float ff = sqrtf(ibuf->x), q = ibuf->y/ff;
			const float Ux = dxt[0]*ff, Vx = dxt[1]*q, Uy = dyt[0]*ff, Vy = dyt[1]*q;
			const float A = Vx*Vx + Vy*Vy;
			const float B = -2.f*(Ux*Vx + Uy*Vy);
			const float C = Ux*Ux + Uy*Uy;
			const float F = A*C - B*B*0.25f;
			float a, b, th, ecc, fProbes;
			BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
			a *= ff;
			b *= ff;
			a = max_ff(a, 1.0f);
			b = max_ff(b, 1.0f);
			fProbes = 2.f*(a / b) - 1.f;
			/* no limit to number of Probes here */
			AFD.iProbes = round_fl_to_int(fProbes);
			if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1);
			AFD.majrad = a/ff;
			AFD.minrad = b/ff;
			AFD.theta = th;
			AFD.dusc = 1.f/ff;
			AFD.dvsc = ff / (float)ibuf->y;
		}
		if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
			/* color & normal */
			filterfunc(texres, ibuf, fx, fy, &AFD);
			val1 = texres->tr + texres->tg + texres->tb;
			filterfunc(&texr, ibuf, fx + dxt[0], fy + dxt[1], &AFD);
			val2 = texr.tr + texr.tg + texr.tb;
			filterfunc(&texr, ibuf, fx + dyt[0], fy + dyt[1], &AFD);
			val3 = texr.tr + texr.tg + texr.tb;
			/* don't switch x or y! */
			texres->nor[0] = val1 - val2;
			texres->nor[1] = val1 - val3;
		}
		else {
			filterfunc(texres, ibuf, fx, fy, &AFD);
			if (tex->texfilter != TXF_EWA) {
				alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
			}
		}
	}

	if (tex->imaflag & TEX_CALCALPHA)
		texres->ta = texres->tin = texres->ta * max_fff(texres->tr, texres->tg, texres->tb);
	else
		texres->tin = texres->ta;
	if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta;
	
	if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
		ibuf->rect -= ibuf->x*ibuf->y;

	if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {	/* normal from color */
		/* The invert of the red channel is to make
		 * the normal map compliant with the outside world.
		 * It needs to be done because in Blender
		 * the normal used in the renderer points inward. It is generated
		 * this way in calc_vertexnormals(). Should this ever change
		 * this negate must be removed. */
		texres->nor[0] = -2.f*(texres->tr - 0.5f);
		texres->nor[1] = 2.f*(texres->tg - 0.5f);
		texres->nor[2] = 2.f*(texres->tb - 0.5f);
	}

	/* de-premul, this is being premulled in shade_input_do_shade()
	 * TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode, so for now commented out
	 * also disabled in imagewraposa() to be able to compare results with blender's default texture filtering */

	/* brecht: tried to fix this, see "TXF alpha" comments */

	/* do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		fx = 1.f/texres->ta;
		texres->tr *= fx;
		texres->tg *= fx;
		texres->tb *= fx;
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}
コード例 #9
0
ファイル: imagetexture.c プロジェクト: wisaac407/blender
int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	TexResult texr;
	float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
	float maxd, pixsize, val1, val2, val3;
	int curmap, retval, imaprepeat, imapextend;

	/* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa() call,
	 * make a local copy here so that original vecs remain untouched */
	copy_v2_v2(dxt, DXT);
	copy_v2_v2(dyt, DYT);

	/* anisotropic filtering */
	if (tex->texfilter != TXF_BOX)
		return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image);

	texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
	
	/* we need to set retval OK, otherwise texture code generates normals itself... */
	retval = texres->nor ? 3 : 1;
	
	/* quick tests */
	if (ibuf==NULL && ima==NULL)
		return retval;
	if (ima) {

		/* hack for icon render */
		if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
			return retval;
		
		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);

		ima->flag|= IMA_USED_FOR_RENDER;
	}
	if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}
	
	/* mipmap test */
	image_mipmap_test(tex, ibuf);

	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((tex->imaflag & TEX_CALCALPHA) == 0) {
				texres->talpha = true;
			}
		}
	}
	
	texr.talpha= texres->talpha;
	
	if (tex->imaflag & TEX_IMAROT) {
		fy= texvec[0];
		fx= texvec[1];
	}
	else {
		fx= texvec[0];
		fy= texvec[1];
	}
	
	if (ibuf->flags & IB_fields) {
		if (R.r.mode & R_FIELDS) {			/* field render */
			if (R.flag & R_SEC_FIELD) {		/* correction for 2nd field */
				/* fac1= 0.5/( (float)ibuf->y ); */
				/* fy-= fac1; */
			}
			else {				/* first field */
				fy+= 0.5f/( (float)ibuf->y );
			}
		}
	}
	
	/* pixel coordinates */

	minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
	maxy = max_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);

	/* tex_sharper has been removed */
	minx= (maxx-minx)/2.0f;
	miny= (maxy-miny)/2.0f;
	
	if (tex->imaflag & TEX_FILTER_MIN) {
		/* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
		float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y);

		if (addval > minx)
			minx= addval;
		if (addval > miny)
			miny= addval;
	}
	else if (tex->filtersize!=1.0f) {
		minx*= tex->filtersize;
		miny*= tex->filtersize;
		
		dxt[0]*= tex->filtersize;
		dxt[1]*= tex->filtersize;
		dyt[0]*= tex->filtersize;
		dyt[1]*= tex->filtersize;
	}

	if (tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny);
	
	if (minx>0.25f) minx= 0.25f;
	else if (minx<0.00001f) minx= 0.00001f;	/* side faces of unit-cube */
	if (miny>0.25f) miny= 0.25f;
	else if (miny<0.00001f) miny= 0.00001f;

	
	/* repeat and clip */
	imaprepeat= (tex->extend==TEX_REPEAT);
	imapextend= (tex->extend==TEX_EXTEND);

	if (tex->extend == TEX_REPEAT) {
		if (tex->flag & (TEX_REPEAT_XMIR|TEX_REPEAT_YMIR)) {
			imaprepeat= 0;
			imapextend= 1;
		}
	}

	if (tex->extend == TEX_CHECKER) {
		int xs, ys, xs1, ys1, xs2, ys2, boundary;
		
		xs= (int)floor(fx);
		ys= (int)floor(fy);
		
		/* both checkers available, no boundary exceptions, checkerdist will eat aliasing */
		if ( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) {
			fx-= xs;
			fy-= ys;
		}
		else if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
		         (tex->flag & TEX_CHECKER_EVEN) == 0)
		{
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
		else {
			
			xs1= (int)floor(fx-minx);
			ys1= (int)floor(fy-miny);
			xs2= (int)floor(fx+minx);
			ys2= (int)floor(fy+miny);
			boundary= (xs1!=xs2) || (ys1!=ys2);

			if (boundary==0) {
				if ( (tex->flag & TEX_CHECKER_ODD)==0) {
					if ((xs + ys) & 1) {
						/* pass */
					}
					else {
						if (ima)
							BKE_image_pool_release_ibuf(ima, ibuf, pool);
						return retval;
					}
				}
				if ( (tex->flag & TEX_CHECKER_EVEN)==0) {
					if ((xs + ys) & 1) {
						if (ima)
							BKE_image_pool_release_ibuf(ima, ibuf, pool);
						return retval;
					}
				}
				fx-= xs;
				fy-= ys;
			}
			else {
				if (tex->flag & TEX_CHECKER_ODD) {
					if ((xs1+ys) & 1) fx-= xs2;
					else fx-= xs1;
					
					if ((ys1+xs) & 1) fy-= ys2;
					else fy-= ys1;
				}
				if (tex->flag & TEX_CHECKER_EVEN) {
					if ((xs1+ys) & 1) fx-= xs1;
					else fx-= xs2;
					
					if ((ys1+xs) & 1) fy-= ys1;
					else fy-= ys2;
				}
			}
		}

		/* scale around center, (0.5, 0.5) */
		if (tex->checkerdist<1.0f) {
			fx= (fx-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			fy= (fy-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			minx/= (1.0f-tex->checkerdist);
			miny/= (1.0f-tex->checkerdist);
		}
	}

	if (tex->extend == TEX_CLIPCUBE) {
		if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f || texvec[2]<-1.0f || texvec[2]>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else if (tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
		if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else {
		if (imapextend) {
			if (fx>1.0f) fx = 1.0f;
			else if (fx<0.0f) fx= 0.0f;
		}
		else {
			if (fx>1.0f) fx -= (int)(fx);
			else if (fx<0.0f) fx+= 1-(int)(fx);
		}
		
		if (imapextend) {
			if (fy>1.0f) fy = 1.0f;
			else if (fy<0.0f) fy= 0.0f;
		}
		else {
			if (fy>1.0f) fy -= (int)(fy);
			else if (fy<0.0f) fy+= 1-(int)(fy);
		}
	}

	/* warning no return! */
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect+= (ibuf->x*ibuf->y);
	}

	/* choice:  */
	if (tex->imaflag & TEX_MIPMAP) {
		ImBuf *previbuf, *curibuf;
		float bumpscale;
		
		dx = minx;
		dy = miny;
		maxd = max_ff(dx, dy);
		if (maxd > 0.5f) maxd = 0.5f;

		pixsize = 1.0f / (float) MIN2(ibuf->x, ibuf->y);
		
		bumpscale= pixsize/maxd;
		if (bumpscale>1.0f) bumpscale= 1.0f;
		else bumpscale*=bumpscale;
		
		curmap= 0;
		previbuf= curibuf= ibuf;
		while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
			if (maxd < pixsize) break;
			previbuf= curibuf;
			curibuf= ibuf->mipmap[curmap];
			pixsize= 1.0f / (float)MIN2(curibuf->x, curibuf->y);
			curmap++;
		}

		if (previbuf!=curibuf || (tex->imaflag & TEX_INTERPOL)) {
			/* sample at least 1 pixel */
			if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
			if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
		}
		
		if (texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
			/* a bit extra filter */
			//minx*= 1.35f;
			//miny*= 1.35f;
			
			boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
			val1= texres->tr+texres->tg+texres->tb;
			boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
			val2= texr.tr + texr.tg + texr.tb;
			boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
			val3= texr.tr + texr.tg + texr.tb;

			/* don't switch x or y! */
			texres->nor[0]= (val1-val2);
			texres->nor[1]= (val1-val3);
			
			if (previbuf!=curibuf) {  /* interpolate */
				
				boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
				
				/* calc rgb */
				dx= 2.0f*(pixsize-maxd)/pixsize;
				if (dx>=1.0f) {
					texres->ta= texr.ta; texres->tb= texr.tb;
					texres->tg= texr.tg; texres->tr= texr.tr;
				}
				else {
					dy= 1.0f-dx;
					texres->tb= dy*texres->tb+ dx*texr.tb;
					texres->tg= dy*texres->tg+ dx*texr.tg;
					texres->tr= dy*texres->tr+ dx*texr.tr;
					texres->ta= dy*texres->ta+ dx*texr.ta;
				}
				
				val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
				boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
				val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
				boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
				val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
				
				texres->nor[0]= (val1-val2);	/* vals have been interpolated above! */
				texres->nor[1]= (val1-val3);
				
				if (dx<1.0f) {
					dy= 1.0f-dx;
					texres->tb= dy*texres->tb+ dx*texr.tb;
					texres->tg= dy*texres->tg+ dx*texr.tg;
					texres->tr= dy*texres->tr+ dx*texr.tr;
					texres->ta= dy*texres->ta+ dx*texr.ta;
				}
			}
			texres->nor[0]*= bumpscale;
			texres->nor[1]*= bumpscale;
		}
		else {
			maxx= fx+minx;
			minx= fx-minx;
			maxy= fy+miny;
			miny= fy-miny;

			boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);

			if (previbuf!=curibuf) {  /* interpolate */
				boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
				
				fx= 2.0f*(pixsize-maxd)/pixsize;
				
				if (fx>=1.0f) {
					texres->ta= texr.ta; texres->tb= texr.tb;
					texres->tg= texr.tg; texres->tr= texr.tr;
				}
				else {
					fy= 1.0f-fx;
					texres->tb= fy*texres->tb+ fx*texr.tb;
					texres->tg= fy*texres->tg+ fx*texr.tg;
					texres->tr= fy*texres->tr+ fx*texr.tr;
					texres->ta= fy*texres->ta+ fx*texr.ta;
				}
			}
		}
	}
	else {
		const int intpol = tex->imaflag & TEX_INTERPOL;
		if (intpol) {
			/* sample 1 pixel minimum */
			if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
			if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
		}

		if (texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
			boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
			val1= texres->tr+texres->tg+texres->tb;
			boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
			val2= texr.tr + texr.tg + texr.tb;
			boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
			val3= texr.tr + texr.tg + texr.tb;

			/* don't switch x or y! */
			texres->nor[0]= (val1-val2);
			texres->nor[1]= (val1-val3);
		}
		else
			boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
	}
	
	if (tex->imaflag & TEX_CALCALPHA) {
		texres->ta = texres->tin = texres->ta * max_fff(texres->tr, texres->tg, texres->tb);
	}
	else {
		texres->tin = texres->ta;
	}

	if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
	
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect-= (ibuf->x*ibuf->y);
	}

	if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
		/* qdn: normal from color
		 * The invert of the red channel is to make
		 * the normal map compliant with the outside world.
		 * It needs to be done because in Blender
		 * the normal used in the renderer points inward. It is generated
		 * this way in calc_vertexnormals(). Should this ever change
		 * this negate must be removed. */
		texres->nor[0] = -2.f*(texres->tr - 0.5f);
		texres->nor[1] = 2.f*(texres->tg - 0.5f);
		texres->nor[2] = 2.f*(texres->tb - 0.5f);
	}

	/* de-premul, this is being premulled in shade_input_do_shade() */
	/* do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		mul_v3_fl(&texres->tr, 1.0f / texres->ta);
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}
コード例 #10
0
ファイル: imagetexture.c プロジェクト: wisaac407/blender
int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	float fx, fy, val1, val2, val3;
	int x, y, retval;
	int xi, yi; /* original values */

	texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
	
	/* we need to set retval OK, otherwise texture code generates normals itself... */
	retval= texres->nor ? 3 : 1;
	
	/* quick tests */
	if (ibuf==NULL && ima==NULL)
		return retval;
	if (ima) {
		
		/* hack for icon render */
		if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
			return retval;

		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);

		ima->flag|= IMA_USED_FOR_RENDER;
	}
	if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}
	
	/* setup mapping */
	if (tex->imaflag & TEX_IMAROT) {
		fy= texvec[0];
		fx= texvec[1];
	}
	else {
		fx= texvec[0];
		fy= texvec[1];
	}
	
	if (tex->extend == TEX_CHECKER) {
		int xs, ys;
		
		xs= (int)floor(fx);
		ys= (int)floor(fy);
		fx-= xs;
		fy-= ys;

		if ( (tex->flag & TEX_CHECKER_ODD) == 0) {
			if ((xs + ys) & 1) {
				/* pass */
			}
			else {
				if (ima)
					BKE_image_pool_release_ibuf(ima, ibuf, pool);
				return retval;
			}
		}
		if ( (tex->flag & TEX_CHECKER_EVEN)==0) {
			if ((xs+ys) & 1) {
				if (ima)
					BKE_image_pool_release_ibuf(ima, ibuf, pool);
				return retval;
			}
		}
		/* scale around center, (0.5, 0.5) */
		if (tex->checkerdist<1.0f) {
			fx= (fx-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			fy= (fy-0.5f)/(1.0f-tex->checkerdist) +0.5f;
		}
	}

	x= xi= (int)floorf(fx*ibuf->x);
	y= yi= (int)floorf(fy*ibuf->y);

	if (tex->extend == TEX_CLIPCUBE) {
		if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0f || texvec[2]>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else if ( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
		if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else {
		if (tex->extend==TEX_EXTEND) {
			if (x>=ibuf->x) x = ibuf->x-1;
			else if (x<0) x= 0;
		}
		else {
			x= x % ibuf->x;
			if (x<0) x+= ibuf->x;
		}
		if (tex->extend==TEX_EXTEND) {
			if (y>=ibuf->y) y = ibuf->y-1;
			else if (y<0) y= 0;
		}
		else {
			y= y % ibuf->y;
			if (y<0) y+= ibuf->y;
		}
	}
	
	/* warning, no return before setting back! */
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect+= (ibuf->x*ibuf->y);
	}

	/* keep this before interpolation [#29761] */
	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((tex->imaflag & TEX_CALCALPHA) == 0) {
				texres->talpha = true;
			}
		}
	}

	/* interpolate */
	if (tex->imaflag & TEX_INTERPOL) {
		float filterx, filtery;
		filterx = (0.5f * tex->filtersize) / ibuf->x;
		filtery = (0.5f * tex->filtersize) / ibuf->y;

		/* important that this value is wrapped [#27782]
		 * this applies the modifications made by the checks above,
		 * back to the floating point values */
		fx -= (float)(xi - x) / (float)ibuf->x;
		fy -= (float)(yi - y) / (float)ibuf->y;

		boxsample(ibuf, fx-filterx, fy-filtery, fx+filterx, fy+filtery, texres, (tex->extend==TEX_REPEAT), (tex->extend==TEX_EXTEND));
	}
	else { /* no filtering */
		ibuf_get_color(&texres->tr, ibuf, x, y);
	}
	
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect-= (ibuf->x*ibuf->y);
	}

	if (texres->nor) {
		if (tex->imaflag & TEX_NORMALMAP) {
			/* qdn: normal from color
			 * The invert of the red channel is to make
			 * the normal map compliant with the outside world.
			 * It needs to be done because in Blender
			 * the normal used in the renderer points inward. It is generated
			 * this way in calc_vertexnormals(). Should this ever change
			 * this negate must be removed. */
			texres->nor[0] = -2.f*(texres->tr - 0.5f);
			texres->nor[1] = 2.f*(texres->tg - 0.5f);
			texres->nor[2] = 2.f*(texres->tb - 0.5f);
		}
		else {
			/* bump: take three samples */
			val1= texres->tr+texres->tg+texres->tb;

			if (x<ibuf->x-1) {
				float col[4];
				ibuf_get_color(col, ibuf, x+1, y);
				val2= (col[0]+col[1]+col[2]);
			}
			else {
				val2= val1;
			}

			if (y<ibuf->y-1) {
				float col[4];
				ibuf_get_color(col, ibuf, x, y+1);
				val3 = (col[0]+col[1]+col[2]);
			}
			else {
				val3 = val1;
			}

			/* do not mix up x and y here! */
			texres->nor[0]= (val1-val2);
			texres->nor[1]= (val1-val3);
		}
	}

	if (texres->talpha) {
		texres->tin = texres->ta;
	}
	else if (tex->imaflag & TEX_CALCALPHA) {
		texres->ta = texres->tin = max_fff(texres->tr, texres->tg, texres->tb);
	}
	else {
		texres->ta = texres->tin = 1.0;
	}
	
	if (tex->flag & TEX_NEGALPHA) {
		texres->ta = 1.0f - texres->ta;
	}

	/* de-premul, this is being premulled in shade_input_do_shade()
	 * do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		fx= 1.0f/texres->ta;
		texres->tr*= fx;
		texres->tg*= fx;
		texres->tb*= fx;
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}
コード例 #11
0
ファイル: drawvolume.c プロジェクト: mcgrathd/blender
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                       GPUTexture *tex, const float min[3], const float max[3],
                       const int res[3], float dx, float UNUSED(base_scale), const float viewnormal[3],
                       GPUTexture *tex_shadow, GPUTexture *tex_flame)
{
	const float ob_sizei[3] = {
	    1.0f / fabsf(ob->size[0]),
	    1.0f / fabsf(ob->size[1]),
	    1.0f / fabsf(ob->size[2])};

	int i, j, k, n, good_index;
	float d /*, d0 */ /* UNUSED */, dd, ds;
	float (*points)[3] = NULL;
	int numpoints = 0;
	float cor[3] = {1.0f, 1.0f, 1.0f};
	int gl_depth = 0, gl_blend = 0;

	int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);

	/* draw slices of smoke is adapted from c++ code authored
	 * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */
	float cv[][3] = {
		{1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
		{1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
	};

	/* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
	float edges[12][2][3] = {
		{{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},

		{{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},

		{{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
	};

	unsigned char *spec_data;
	float *spec_pixels;
	GPUTexture *tex_spec;
	GPUProgram *smoke_program;
	int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE;
	float size[3];

	if (!tex) {
		printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
		return;
	}

#ifdef DEBUG_DRAW_TIME
	TIMEIT_START(draw);
#endif

	/* generate flame spectrum texture */
#define SPEC_WIDTH 256
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
	spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char));
	flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
	spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float));
	for (i = 0; i < 16; i++) {
		for (j = 0; j < 16; j++) {
			for (k = 0; k < SPEC_WIDTH; k++) {
				int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
				if (k >= FIRE_THRESH) {
					spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f;
					spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f;
					spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f;
					spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
					        (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
				}
				else {
					spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f;
				}
			}
		}
	}

	tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);

#undef SPEC_WIDTH
#undef FIRE_THRESH
#undef MAX_FIRE_ALPHA
#undef FULL_ON_FIRE

	sub_v3_v3v3(size, max, min);

	/* maxx, maxy, maxz */
	cv[0][0] = max[0];
	cv[0][1] = max[1];
	cv[0][2] = max[2];
	/* minx, maxy, maxz */
	cv[1][0] = min[0];
	cv[1][1] = max[1];
	cv[1][2] = max[2];
	/* minx, miny, maxz */
	cv[2][0] = min[0];
	cv[2][1] = min[1];
	cv[2][2] = max[2];
	/* maxx, miny, maxz */
	cv[3][0] = max[0];
	cv[3][1] = min[1];
	cv[3][2] = max[2];

	/* maxx, maxy, minz */
	cv[4][0] = max[0];
	cv[4][1] = max[1];
	cv[4][2] = min[2];
	/* minx, maxy, minz */
	cv[5][0] = min[0];
	cv[5][1] = max[1];
	cv[5][2] = min[2];
	/* minx, miny, minz */
	cv[6][0] = min[0];
	cv[6][1] = min[1];
	cv[6][2] = min[2];
	/* maxx, miny, minz */
	cv[7][0] = max[0];
	cv[7][1] = min[1];
	cv[7][2] = min[2];

	copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */
	copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */
	copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */
	copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */
	copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */

	// printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
	// printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);

	edges[0][1][2] = size[2];
	edges[1][1][2] = size[2];
	edges[2][1][2] = size[2];
	edges[3][1][2] = size[2];

	edges[4][1][1] = size[1];
	edges[5][1][1] = size[1];
	edges[6][1][1] = size[1];
	edges[7][1][1] = size[1];

	edges[8][1][0] = size[0];
	edges[9][1][0] = size[0];
	edges[10][1][0] = size[0];
	edges[11][1][0] = size[0];

	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);

	/* find cube vertex that is closest to the viewer */
	for (i = 0; i < 8; i++) {
		float x, y, z;

		x = cv[i][0] - viewnormal[0] * size[0] * 0.5f;
		y = cv[i][1] - viewnormal[1] * size[1] * 0.5f;
		z = cv[i][2] - viewnormal[2] * size[2] * 0.5f;

		if ((x >= min[0]) && (x <= max[0]) &&
		    (y >= min[1]) && (y <= max[1]) &&
		    (z >= min[2]) && (z <= max[2]))
		{
			break;
		}
	}

	if (i >= 8) {
		/* fallback, avoid using buffer over-run */
		i = 0;
	}

	// printf("i: %d\n", i);
	// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);

	smoke_program = GPU_shader_get_builtin_program(progtype);
	if (smoke_program) {
		GPU_program_bind(smoke_program);

		/* cell spacing */
		GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0);
		/* custom parameter for smoke style (higher = thicker) */
		if (sds->active_fields & SM_ACTIVE_COLORS)
			GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0);
		else
			GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
	}
	else
		printf("Your gfx card does not support 3D View smoke drawing.\n");

	GPU_texture_bind(tex, 0);
	if (tex_shadow)
		GPU_texture_bind(tex_shadow, 1);
	else
		printf("No volume shadow\n");

	if (tex_flame) {
		GPU_texture_bind(tex_flame, 2);
		GPU_texture_bind(tex_spec, 3);
	}

	if (!GPU_non_power_of_two_support()) {
		cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]);
		cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]);
		cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]);
	}

	cor[0] /= size[0];
	cor[1] /= size[1];
	cor[2] /= size[2];

	/* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
	 * (a,b,c), the plane normal, are given by viewdir
	 * d is the parameter along the view direction. the first d is given by
	 * inserting previously found vertex into the plane equation */

	/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
	ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
	dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
	n = 0;
	good_index = i;

	// printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);

	points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview");

	while (1) {
		float p0[3];
		float tmp_point[3], tmp_point2[3];

		if (dd * (float)n > ds)
			break;

		copy_v3_v3(tmp_point, viewnormal);
		mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n));
		add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
		d = dot_v3v3(tmp_point2, viewnormal);

		// printf("my d: %f\n", d);

		/* intersect_edges returns the intersection points of all cube edges with
		 * the given plane that lie within the cube */
		numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);

		// printf("points: %d\n", numpoints);

		if (numpoints > 2) {
			copy_v3_v3(p0, points[0]);

			/* sort points to get a convex polygon */
			for (i = 1; i < numpoints - 1; i++) {
				for (j = i + 1; j < numpoints; j++) {
					if (!convex(p0, viewnormal, points[j], points[i])) {
						swap_v3_v3(points[i], points[j]);
					}
				}
			}

			/* render fire slice */
			if (use_fire) {
				if (GLEW_VERSION_1_4)
					glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
				else
					glBlendFunc(GL_SRC_ALPHA, GL_ONE);

				GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
				glBegin(GL_POLYGON);
				glColor3f(1.0, 1.0, 1.0);
				for (i = 0; i < numpoints; i++) {
					glTexCoord3d((points[i][0] - min[0]) * cor[0],
					             (points[i][1] - min[1]) * cor[1],
					             (points[i][2] - min[2]) * cor[2]);
					glVertex3f(points[i][0] * ob_sizei[0],
					           points[i][1] * ob_sizei[1],
					           points[i][2] * ob_sizei[2]);
				}
				glEnd();
			}

			/* render smoke slice */
			if (GLEW_VERSION_1_4)
				glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
			else
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i][0] - min[0]) * cor[0],
				             (points[i][1] - min[1]) * cor[1],
				             (points[i][2] - min[2]) * cor[2]);
				glVertex3f(points[i][0] * ob_sizei[0],
				           points[i][1] * ob_sizei[1],
				           points[i][2] * ob_sizei[2]);
			}
			glEnd();
		}
		n++;
	}

#ifdef DEBUG_DRAW_TIME
	printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
	TIMEIT_END(draw);
#endif

	if (tex_shadow)
		GPU_texture_unbind(tex_shadow);
	GPU_texture_unbind(tex);
	if (tex_flame) {
		GPU_texture_unbind(tex_flame);
		GPU_texture_unbind(tex_spec);
	}
	GPU_texture_free(tex_spec);

	free(spec_data);
	free(spec_pixels);

	if (smoke_program)
		GPU_program_unbind(smoke_program);


	MEM_freeN(points);

	if (!gl_blend) {
		glDisable(GL_BLEND);
	}

	if (gl_depth) {
		glEnable(GL_DEPTH_TEST);
	}
}