/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. */ /** \file * \ingroup render */ /* Global includes */ #include #include #include #include #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_camera_types.h" #include "BKE_camera.h" /* this module */ #include "pipeline.h" #include "render_types.h" /* Own includes */ #include "initrender.h" /* ****************** MASKS and LUTS **************** */ static float filt_quadratic(float x) { if (x < 0.0f) { x = -x; } if (x < 0.5f) { return 0.75f - (x * x); } if (x < 1.5f) { return 0.50f * (x - 1.5f) * (x - 1.5f); } return 0.0f; } static float filt_cubic(float x) { float x2 = x * x; if (x < 0.0f) { x = -x; } if (x < 1.0f) { return 0.5f * x * x2 - x2 + 2.0f / 3.0f; } if (x < 2.0f) { return (2.0f - x) * (2.0f - x) * (2.0f - x) / 6.0f; } return 0.0f; } static float filt_catrom(float x) { float x2 = x * x; if (x < 0.0f) { x = -x; } if (x < 1.0f) { return 1.5f * x2 * x - 2.5f * x2 + 1.0f; } if (x < 2.0f) { return -0.5f * x2 * x + 2.5f * x2 - 4.0f * x + 2.0f; } return 0.0f; } static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */ { float b = 1.0f / 3.0f, c = 1.0f / 3.0f; float p0 = (6.0f - 2.0f * b) / 6.0f; float p2 = (-18.0f + 12.0f * b + 6.0f * c) / 6.0f; float p3 = (12.0f - 9.0f * b - 6.0f * c) / 6.0f; float q0 = (8.0f * b + 24.0f * c) / 6.0f; float q1 = (-12.0f * b - 48.0f * c) / 6.0f; float q2 = (6.0f * b + 30.0f * c) / 6.0f; float q3 = (-b - 6.0f * c) / 6.0f; if (x < -2.0f) { return 0.0f; } if (x < -1.0f) { return (q0 - x * (q1 - x * (q2 - x * q3))); } if (x < 0.0f) { return (p0 + x * x * (p2 - x * p3)); } if (x < 1.0f) { return (p0 + x * x * (p2 + x * p3)); } if (x < 2.0f) { return (q0 + x * (q1 + x * (q2 + x * q3))); } return 0.0f; } /* x ranges from -1 to 1 */ float RE_filter_value(int type, float x) { float gaussfac = 1.6f; x = fabsf(x); switch (type) { case R_FILTER_BOX: if (x > 1.0f) { return 0.0f; } return 1.0f; case R_FILTER_TENT: if (x > 1.0f) { return 0.0f; } return 1.0f - x; case R_FILTER_GAUSS: { const float two_gaussfac2 = 2.0f * gaussfac * gaussfac; x *= 3.0f * gaussfac; return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2); } case R_FILTER_MITCH: return filt_mitchell(x * gaussfac); case R_FILTER_QUAD: return filt_quadratic(x * gaussfac); case R_FILTER_CUBIC: return filt_cubic(x * gaussfac); case R_FILTER_CATROM: return filt_catrom(x * gaussfac); } return 0.0f; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ struct Object *RE_GetCamera(Render *re) { Object *camera = re->camera_override ? re->camera_override : re->scene->camera; return BKE_camera_multiview_render(re->scene, camera, re->viewname); } void RE_SetOverrideCamera(Render *re, Object *cam_ob) { re->camera_override = cam_ob; } /** * Per render, there's one persistent view-plane. Parts will set their own view-planes. * * \note call this after #RE_InitState(). */ void RE_SetCamera(Render *re, Object *cam_ob) { CameraParams params; /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, cam_ob); BKE_camera_multiview_params(&re->r, ¶ms, cam_ob, re->viewname); /* Compute matrix, view-plane, etc. */ BKE_camera_params_compute_viewplane(¶ms, re->winx, re->winy, re->r.xasp, re->r.yasp); BKE_camera_params_compute_matrix(¶ms); /* extract results */ copy_m4_m4(re->winmat, params.winmat); re->clip_start = params.clip_start; re->clip_end = params.clip_end; re->viewplane = params.viewplane; } void RE_GetCameraWindow(struct Render *re, struct Object *camera, float r_winmat[4][4]) { RE_SetCamera(re, camera); copy_m4_m4(r_winmat, re->winmat); } /* Must be called after RE_GetCameraWindow(), does not change re->winmat. */ void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4]) { CameraParams params; params.is_ortho = re->winmat[3][3] != 0.0f; params.clip_start = re->clip_start; params.clip_end = re->clip_end; params.viewplane = re->viewplane; overscan *= max_ff(BLI_rctf_size_x(¶ms.viewplane), BLI_rctf_size_y(¶ms.viewplane)); params.viewplane.xmin -= overscan; params.viewplane.xmax += overscan; params.viewplane.ymin -= overscan; params.viewplane.ymax += overscan; BKE_camera_params_compute_matrix(¶ms); copy_m4_m4(r_winmat, params.winmat); } void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_modelmat[4][4]) { BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_modelmat); } void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect) { *r_viewplane = re->viewplane; /* make disprect zero when no border render, is needed to detect changes in 3d view render */ if (re->r.mode & R_BORDER) { *r_disprect = re->disprect; } else { BLI_rcti_init(r_disprect, 0, 0, 0, 0); } } /* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */ void RE_parts_free(Render *re) { if (re->parts) { BLI_ghash_free(re->parts, NULL, MEM_freeN); re->parts = NULL; } } void RE_parts_clamp(Render *re) { /* part size */ re->partx = max_ii(1, min_ii(re->r.tilex, re->rectx)); re->party = max_ii(1, min_ii(re->r.tiley, re->recty)); } void RE_parts_init(Render *re) { int nr, xd, yd, partx, party, xparts, yparts; int xminb, xmaxb, yminb, ymaxb; RE_parts_free(re); re->parts = BLI_ghash_new( BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, "render parts"); /* Just for readable code. */ xminb = re->disprect.xmin; yminb = re->disprect.ymin; xmaxb = re->disprect.xmax; ymaxb = re->disprect.ymax; RE_parts_clamp(re); partx = re->partx; party = re->party; /* part count */ xparts = (re->rectx + partx - 1) / partx; yparts = (re->recty + party - 1) / party; for (nr = 0; nr < xparts * yparts; nr++) { rcti disprect; int rectx, recty; xd = (nr % xparts); yd = (nr - xd) / xparts; disprect.xmin = xminb + xd * partx; disprect.ymin = yminb + yd * party; /* ensure we cover the entire picture, so last parts go to end */ if (xd < xparts - 1) { disprect.xmax = disprect.xmin + partx; if (disprect.xmax > xmaxb) { disprect.xmax = xmaxb; } } else { disprect.xmax = xmaxb; } if (yd < yparts - 1) { disprect.ymax = disprect.ymin + party; if (disprect.ymax > ymaxb) { disprect.ymax = ymaxb; } } else { disprect.ymax = ymaxb; } rectx = BLI_rcti_size_x(&disprect); recty = BLI_rcti_size_y(&disprect); /* so, now can we add this part? */ if (rectx > 0 && recty > 0) { RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part"); pa->disprect = disprect; pa->rectx = rectx; pa->recty = recty; BLI_ghash_insert(re->parts, &pa->disprect, pa); } } }