|
Blender
V2.59
|
00001 /* 00002 * $Id: object_bake.c 38555 2011-07-21 08:10:34Z nazgul $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2004 by Blender Foundation 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): Morten Mikkelsen, 00026 * Sergey Sharybin 00027 * 00028 * ***** END GPL LICENSE BLOCK ***** 00029 */ 00030 00036 /* 00037 meshtools.c: no editmode (violated already :), tools operating on meshes 00038 */ 00039 00040 #include <string.h> 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "DNA_scene_types.h" 00045 #include "DNA_screen_types.h" 00046 #include "DNA_space_types.h" 00047 #include "DNA_world_types.h" 00048 #include "DNA_object_types.h" 00049 #include "DNA_mesh_types.h" 00050 #include "DNA_meshdata_types.h" 00051 00052 #include "BLI_blenlib.h" 00053 #include "BLI_threads.h" 00054 #include "BLI_utildefines.h" 00055 #include "BLI_math.h" 00056 #include "BLI_math_geom.h" 00057 00058 #include "BKE_blender.h" 00059 #include "BKE_context.h" 00060 #include "BKE_global.h" 00061 #include "BKE_image.h" 00062 #include "BKE_main.h" 00063 #include "BKE_multires.h" 00064 #include "BKE_report.h" 00065 #include "BKE_cdderivedmesh.h" 00066 #include "BKE_modifier.h" 00067 #include "BKE_DerivedMesh.h" 00068 #include "BKE_subsurf.h" 00069 00070 #include "RE_pipeline.h" 00071 #include "RE_shader_ext.h" 00072 00073 #include "PIL_time.h" 00074 00075 #include "IMB_imbuf_types.h" 00076 #include "IMB_imbuf.h" 00077 00078 #include "GPU_draw.h" /* GPU_free_image */ 00079 00080 #include "WM_api.h" 00081 #include "WM_types.h" 00082 00083 #include "ED_object.h" 00084 00085 #include "object_intern.h" 00086 00087 /* ****************** multires BAKING ********************** */ 00088 00089 /* holder of per-object data needed for bake job 00090 needed to make job totally thread-safe */ 00091 typedef struct MultiresBakerJobData { 00092 struct MultiresBakerJobData *next, *prev; 00093 DerivedMesh *lores_dm, *hires_dm; 00094 int simple, lvl, tot_lvl; 00095 } MultiresBakerJobData; 00096 00097 /* data passing to multires-baker job */ 00098 typedef struct { 00099 ListBase data; 00100 int bake_clear, bake_filter; 00101 short mode, use_lores_mesh; 00102 } MultiresBakeJob; 00103 00104 /* data passing to multires baker */ 00105 typedef struct { 00106 DerivedMesh *lores_dm, *hires_dm; 00107 int simple, lvl, tot_lvl, bake_filter; 00108 short mode, use_lores_mesh; 00109 00110 int tot_obj, tot_image; 00111 ListBase image; 00112 00113 int baked_objects, baked_faces; 00114 00115 short *stop; 00116 short *do_update; 00117 float *progress; 00118 } MultiresBakeRender; 00119 00120 typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, 00121 const int face_index, const int lvl, const float st[2], 00122 float tangmat[3][3], const int x, const int y); 00123 00124 typedef void* (*MInitBakeData)(MultiresBakeRender *bkr, Image* ima); 00125 typedef void (*MApplyBakeData)(void *bake_data); 00126 typedef void (*MFreeBakeData)(void *bake_data); 00127 00128 typedef struct { 00129 MVert *mvert; 00130 MFace *mface; 00131 MTFace *mtface; 00132 float *pvtangent; 00133 float *precomputed_normals; 00134 int w, h; 00135 int face_index; 00136 int i0, i1, i2; 00137 DerivedMesh *lores_dm, *hires_dm; 00138 int lvl; 00139 void *bake_data; 00140 MPassKnownData pass_data; 00141 } MResolvePixelData; 00142 00143 typedef void (*MFlushPixel)(const MResolvePixelData *data, const int x, const int y); 00144 00145 typedef struct { 00146 int w, h; 00147 char *texels; 00148 const MResolvePixelData *data; 00149 MFlushPixel flush_pixel; 00150 } MBakeRast; 00151 00152 typedef struct { 00153 float *heights; 00154 float height_min, height_max; 00155 Image *ima; 00156 DerivedMesh *ssdm; 00157 } MHeightBakeData; 00158 00159 static void multiresbake_get_normal(const MResolvePixelData *data, float norm[], const int face_num, const int vert_index) 00160 { 00161 unsigned int indices[]= {data->mface[face_num].v1, data->mface[face_num].v2, 00162 data->mface[face_num].v3, data->mface[face_num].v4}; 00163 const int smoothnormal= (data->mface[face_num].flag & ME_SMOOTH); 00164 00165 if(!smoothnormal) { /* flat */ 00166 if(data->precomputed_normals) { 00167 copy_v3_v3(norm, &data->precomputed_normals[3*face_num]); 00168 } else { 00169 float nor[3]; 00170 float *p0, *p1, *p2; 00171 const int iGetNrVerts= data->mface[face_num].v4!=0 ? 4 : 3; 00172 00173 p0= data->mvert[indices[0]].co; 00174 p1= data->mvert[indices[1]].co; 00175 p2= data->mvert[indices[2]].co; 00176 00177 if(iGetNrVerts==4) { 00178 float *p3= data->mvert[indices[3]].co; 00179 normal_quad_v3(nor, p0, p1, p2, p3); 00180 } else { 00181 normal_tri_v3(nor, p0, p1, p2); 00182 } 00183 00184 copy_v3_v3(norm, nor); 00185 } 00186 } else { 00187 short *no= data->mvert[indices[vert_index]].no; 00188 00189 normal_short_to_float_v3(norm, no); 00190 normalize_v3(norm); 00191 } 00192 } 00193 00194 static void init_bake_rast(MBakeRast *bake_rast, const ImBuf *ibuf, const MResolvePixelData *data, MFlushPixel flush_pixel) 00195 { 00196 memset(bake_rast, 0, sizeof(MBakeRast)); 00197 00198 bake_rast->texels = ibuf->userdata; 00199 bake_rast->w= ibuf->x; 00200 bake_rast->h= ibuf->y; 00201 bake_rast->data= data; 00202 bake_rast->flush_pixel= flush_pixel; 00203 } 00204 00205 static void flush_pixel(const MResolvePixelData *data, const int x, const int y) 00206 { 00207 float st[2]= {(x+0.5f)/data->w, (y+0.5f)/data->h}; 00208 float *st0, *st1, *st2; 00209 float *tang0, *tang1, *tang2; 00210 float no0[3], no1[3], no2[3]; 00211 float fUV[2], from_tang[3][3], to_tang[3][3]; 00212 float u, v, w, sign; 00213 int r; 00214 00215 const int i0= data->i0; 00216 const int i1= data->i1; 00217 const int i2= data->i2; 00218 00219 st0= data->mtface[data->face_index].uv[i0]; 00220 st1= data->mtface[data->face_index].uv[i1]; 00221 st2= data->mtface[data->face_index].uv[i2]; 00222 00223 tang0= data->pvtangent + data->face_index*16 + i0*4; 00224 tang1= data->pvtangent + data->face_index*16 + i1*4; 00225 tang2= data->pvtangent + data->face_index*16 + i2*4; 00226 00227 multiresbake_get_normal(data, no0, data->face_index, i0); /* can optimize these 3 into one call */ 00228 multiresbake_get_normal(data, no1, data->face_index, i1); 00229 multiresbake_get_normal(data, no2, data->face_index, i2); 00230 00231 resolve_tri_uv(fUV, st, st0, st1, st2); 00232 00233 u= fUV[0]; 00234 v= fUV[1]; 00235 w= 1-u-v; 00236 00237 /* the sign is the same at all face vertices for any non degenerate face. 00238 Just in case we clamp the interpolated value though. */ 00239 sign= (tang0[3]*u + tang1[3]*v + tang2[3]*w)<0 ? (-1.0f) : 1.0f; 00240 00241 /* this sequence of math is designed specifically as is with great care 00242 to be compatible with our shader. Please don't change without good reason. */ 00243 for(r= 0; r<3; r++) { 00244 from_tang[0][r]= tang0[r]*u + tang1[r]*v + tang2[r]*w; 00245 from_tang[2][r]= no0[r]*u + no1[r]*v + no2[r]*w; 00246 } 00247 00248 cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* B = sign * cross(N, T) */ 00249 mul_v3_fl(from_tang[1], sign); 00250 invert_m3_m3(to_tang, from_tang); 00251 /* sequence end */ 00252 00253 data->pass_data(data->lores_dm, data->hires_dm, data->bake_data, 00254 data->face_index, data->lvl, st, to_tang, x, y); 00255 } 00256 00257 static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y) 00258 { 00259 const int w= bake_rast->w; 00260 const int h= bake_rast->h; 00261 00262 if(x>=0 && x<w && y>=0 && y<h) { 00263 if((bake_rast->texels[y*w+x])==0) { 00264 flush_pixel(bake_rast->data, x, y); 00265 bake_rast->texels[y*w+x]= FILTER_MASK_USED; 00266 } 00267 } 00268 } 00269 00270 static void rasterize_half(const MBakeRast *bake_rast, 00271 const float s0_s, const float t0_s, const float s1_s, const float t1_s, 00272 const float s0_l, const float t0_l, const float s1_l, const float t1_l, 00273 const int y0_in, const int y1_in, const int is_mid_right) 00274 { 00275 const int s_stable= fabsf(t1_s-t0_s)>FLT_EPSILON ? 1 : 0; 00276 const int l_stable= fabsf(t1_l-t0_l)>FLT_EPSILON ? 1 : 0; 00277 const int w= bake_rast->w; 00278 const int h= bake_rast->h; 00279 int y, y0, y1; 00280 00281 if(y1_in<=0 || y0_in>=h) 00282 return; 00283 00284 y0= y0_in<0 ? 0 : y0_in; 00285 y1= y1_in>=h ? h : y1_in; 00286 00287 for(y= y0; y<y1; y++) { 00288 /*-b(x-x0) + a(y-y0) = 0 */ 00289 int iXl, iXr, x; 00290 float x_l= s_stable!=0 ? (s0_s + (((s1_s-s0_s)*(y-t0_s))/(t1_s-t0_s))) : s0_s; 00291 float x_r= l_stable!=0 ? (s0_l + (((s1_l-s0_l)*(y-t0_l))/(t1_l-t0_l))) : s0_l; 00292 00293 if(is_mid_right!=0) 00294 SWAP(float, x_l, x_r); 00295 00296 iXl= (int)ceilf(x_l); 00297 iXr= (int)ceilf(x_r); 00298 00299 if(iXr>0 && iXl<w) { 00300 iXl= iXl<0?0:iXl; 00301 iXr= iXr>=w?w:iXr; 00302 00303 for(x= iXl; x<iXr; x++) 00304 set_rast_triangle(bake_rast, x, y); 00305 } 00306 } 00307 } 00308 00309 static void bake_rasterize(const MBakeRast *bake_rast, const float st0_in[2], const float st1_in[2], const float st2_in[2]) 00310 { 00311 const int w= bake_rast->w; 00312 const int h= bake_rast->h; 00313 float slo= st0_in[0]*w - 0.5f; 00314 float tlo= st0_in[1]*h - 0.5f; 00315 float smi= st1_in[0]*w - 0.5f; 00316 float tmi= st1_in[1]*h - 0.5f; 00317 float shi= st2_in[0]*w - 0.5f; 00318 float thi= st2_in[1]*h - 0.5f; 00319 int is_mid_right= 0, ylo, yhi, yhi_beg; 00320 00321 /* skip degenerates */ 00322 if((slo==smi && tlo==tmi) || (slo==shi && tlo==thi) || (smi==shi && tmi==thi)) 00323 return; 00324 00325 /* sort by T */ 00326 if(tlo>tmi && tlo>thi) { 00327 SWAP(float, shi, slo); 00328 SWAP(float, thi, tlo); 00329 } else if(tmi>thi) { 00330 SWAP(float, shi, smi); 00331 SWAP(float, thi, tmi); 00332 } 00333 00334 if(tlo>tmi) { 00335 SWAP(float, slo, smi); 00336 SWAP(float, tlo, tmi); 00337 } 00338 00339 /* check if mid point is to the left or to the right of the lo-hi edge */ 00340 is_mid_right= (-(shi-slo)*(tmi-thi) + (thi-tlo)*(smi-shi))>0 ? 1 : 0; 00341 ylo= (int) ceilf(tlo); 00342 yhi_beg= (int) ceilf(tmi); 00343 yhi= (int) ceilf(thi); 00344 00345 /*if(fTmi>ceilf(fTlo))*/ 00346 rasterize_half(bake_rast, slo, tlo, smi, tmi, slo, tlo, shi, thi, ylo, yhi_beg, is_mid_right); 00347 rasterize_half(bake_rast, smi, tmi, shi, thi, slo, tlo, shi, thi, yhi_beg, yhi, is_mid_right); 00348 } 00349 00350 static int multiresbake_test_break(MultiresBakeRender *bkr) 00351 { 00352 if(!bkr->stop) { 00353 /* this means baker is executed outside from job system */ 00354 return 0; 00355 } 00356 00357 return G.afbreek; 00358 } 00359 00360 static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData passKnownData, 00361 MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData) 00362 { 00363 DerivedMesh *dm= bkr->lores_dm; 00364 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00365 const int lvl= bkr->lvl; 00366 const int tot_face= dm->getNumFaces(dm); 00367 MVert *mvert= dm->getVertArray(dm); 00368 MFace *mface= dm->getFaceArray(dm); 00369 MTFace *mtface= dm->getFaceDataArray(dm, CD_MTFACE); 00370 float *pvtangent= NULL; 00371 00372 if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) 00373 DM_add_tangent_layer(dm); 00374 00375 pvtangent= DM_get_face_data_layer(dm, CD_TANGENT); 00376 00377 if(tot_face > 0) { /* sanity check */ 00378 int f= 0; 00379 MBakeRast bake_rast; 00380 MResolvePixelData data={NULL}; 00381 00382 data.mface= mface; 00383 data.mvert= mvert; 00384 data.mtface= mtface; 00385 data.pvtangent= pvtangent; 00386 data.precomputed_normals= dm->getFaceDataArray(dm, CD_NORMAL); /* don't strictly need this */ 00387 data.w= ibuf->x; 00388 data.h= ibuf->y; 00389 data.lores_dm= dm; 00390 data.hires_dm= bkr->hires_dm; 00391 data.lvl= lvl; 00392 data.pass_data= passKnownData; 00393 00394 if(initBakeData) 00395 data.bake_data= initBakeData(bkr, ima); 00396 00397 init_bake_rast(&bake_rast, ibuf, &data, flush_pixel); 00398 00399 for(f= 0; f<tot_face; f++) { 00400 MTFace *mtfate= &mtface[f]; 00401 int verts[3][2], nr_tris, t; 00402 00403 if(multiresbake_test_break(bkr)) 00404 break; 00405 00406 if(mtfate->tpage!=ima) 00407 continue; 00408 00409 data.face_index= f; 00410 00411 /* might support other forms of diagonal splits later on such as 00412 split by shortest diagonal.*/ 00413 verts[0][0]=0; 00414 verts[1][0]=1; 00415 verts[2][0]=2; 00416 00417 verts[0][1]=0; 00418 verts[1][1]=2; 00419 verts[2][1]=3; 00420 00421 nr_tris= mface[f].v4!=0 ? 2 : 1; 00422 for(t= 0; t<nr_tris; t++) { 00423 data.i0= verts[0][t]; 00424 data.i1= verts[1][t]; 00425 data.i2 =verts[2][t]; 00426 00427 bake_rasterize(&bake_rast, mtfate->uv[data.i0], mtfate->uv[data.i1], mtfate->uv[data.i2]); 00428 } 00429 00430 bkr->baked_faces++; 00431 00432 if(bkr->do_update) 00433 *bkr->do_update= 1; 00434 00435 if(bkr->progress) 00436 *bkr->progress= ((float)bkr->baked_objects + (float)bkr->baked_faces / tot_face) / bkr->tot_obj; 00437 } 00438 00439 if(applyBakeData) 00440 applyBakeData(data.bake_data); 00441 00442 if(freeBakeData) 00443 freeBakeData(data.bake_data); 00444 } 00445 } 00446 00447 static void interp_bilinear_quad_data(float data[4][3], float u, float v, float res[3]) 00448 { 00449 float vec[3]; 00450 00451 copy_v3_v3(res, data[0]); 00452 mul_v3_fl(res, (1-u)*(1-v)); 00453 copy_v3_v3(vec, data[1]); 00454 mul_v3_fl(vec, u*(1-v)); add_v3_v3(res, vec); 00455 copy_v3_v3(vec, data[2]); 00456 mul_v3_fl(vec, u*v); add_v3_v3(res, vec); 00457 copy_v3_v3(vec, data[3]); 00458 mul_v3_fl(vec, (1-u)*v); add_v3_v3(res, vec); 00459 } 00460 00461 static void interp_barycentric_tri_data(float data[3][3], float u, float v, float res[3]) 00462 { 00463 float vec[3]; 00464 00465 copy_v3_v3(res, data[0]); 00466 mul_v3_fl(res, u); 00467 copy_v3_v3(vec, data[1]); 00468 mul_v3_fl(vec, v); add_v3_v3(res, vec); 00469 copy_v3_v3(vec, data[2]); 00470 mul_v3_fl(vec, 1.0f-u-v); add_v3_v3(res, vec); 00471 } 00472 00473 /* mode = 0: interpolate normals, 00474 mode = 1: interpolate coord */ 00475 static void interp_bilinear_grid(DMGridData *grid, int grid_size, float crn_x, float crn_y, int mode, float res[3]) 00476 { 00477 int x0, x1, y0, y1; 00478 float u, v; 00479 float data[4][3]; 00480 00481 x0= (int) crn_x; 00482 x1= x0>=(grid_size-1) ? (grid_size-1) : (x0+1); 00483 00484 y0= (int) crn_y; 00485 y1= y0>=(grid_size-1) ? (grid_size-1) : (y0+1); 00486 00487 u= crn_x-x0; 00488 v= crn_y-y0; 00489 00490 if(mode == 0) { 00491 copy_v3_v3(data[0], grid[y0 * grid_size + x0].no); 00492 copy_v3_v3(data[1], grid[y0 * grid_size + x1].no); 00493 copy_v3_v3(data[2], grid[y1 * grid_size + x1].no); 00494 copy_v3_v3(data[3], grid[y1 * grid_size + x0].no); 00495 } else { 00496 copy_v3_v3(data[0], grid[y0 * grid_size + x0].co); 00497 copy_v3_v3(data[1], grid[y0 * grid_size + x1].co); 00498 copy_v3_v3(data[2], grid[y1 * grid_size + x1].co); 00499 copy_v3_v3(data[3], grid[y1 * grid_size + x0].co); 00500 } 00501 00502 interp_bilinear_quad_data(data, u, v, res); 00503 } 00504 00505 static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, const int lvl, const int face_index, const float u, const float v, float co[3], float n[3]) 00506 { 00507 MFace mface; 00508 DMGridData **grid_data; 00509 float crn_x, crn_y; 00510 int grid_size, S, face_side; 00511 int *grid_offset, g_index; 00512 00513 lodm->getFace(lodm, face_index, &mface); 00514 00515 grid_size= hidm->getGridSize(hidm); 00516 grid_data= hidm->getGridData(hidm); 00517 grid_offset= hidm->getGridOffset(hidm); 00518 00519 face_side= (grid_size<<1)-1; 00520 00521 if(lvl==0) { 00522 g_index= grid_offset[face_index]; 00523 S= mdisp_rot_face_to_crn(mface.v4 ? 4 : 3, face_side, u*(face_side-1), v*(face_side-1), &crn_x, &crn_y); 00524 } else { 00525 const int *index= lodm->getFaceDataArray(lodm, CD_ORIGINDEX); 00526 int side= (1 << (lvl-1)) + 1; 00527 int grid_index= index[face_index]; 00528 int loc_offs= face_index % (1<<(2*lvl)); 00529 int cell_index= loc_offs % ((side-1)*(side-1)); 00530 int cell_side= grid_size / (side-1); 00531 int row= cell_index / (side-1); 00532 int col= cell_index % (side-1); 00533 00534 S= face_index / (1<<(2*(lvl-1))) - grid_offset[grid_index]; 00535 g_index= grid_offset[grid_index]; 00536 00537 crn_y= (row * cell_side) + u * cell_side; 00538 crn_x= (col * cell_side) + v * cell_side; 00539 } 00540 00541 CLAMP(crn_x, 0.0f, grid_size); 00542 CLAMP(crn_y, 0.0f, grid_size); 00543 00544 if(n != NULL) 00545 interp_bilinear_grid(grid_data[g_index + S], grid_size, crn_x, crn_y, 0, n); 00546 00547 if(co != NULL) 00548 interp_bilinear_grid(grid_data[g_index + S], grid_size, crn_x, crn_y, 1, co); 00549 } 00550 00551 /* mode = 0: interpolate normals, 00552 mode = 1: interpolate coord */ 00553 static void interp_bilinear_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3]) 00554 { 00555 float data[4][3]; 00556 00557 if(mode == 0) { 00558 dm->getVertNo(dm, mface->v1, data[0]); 00559 dm->getVertNo(dm, mface->v2, data[1]); 00560 dm->getVertNo(dm, mface->v3, data[2]); 00561 dm->getVertNo(dm, mface->v4, data[3]); 00562 } else { 00563 dm->getVertCo(dm, mface->v1, data[0]); 00564 dm->getVertCo(dm, mface->v2, data[1]); 00565 dm->getVertCo(dm, mface->v3, data[2]); 00566 dm->getVertCo(dm, mface->v4, data[3]); 00567 } 00568 00569 interp_bilinear_quad_data(data, u, v, res); 00570 } 00571 00572 /* mode = 0: interpolate normals, 00573 mode = 1: interpolate coord */ 00574 static void interp_barycentric_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3]) 00575 { 00576 float data[3][3]; 00577 00578 if(mode == 0) { 00579 dm->getVertNo(dm, mface->v1, data[0]); 00580 dm->getVertNo(dm, mface->v2, data[1]); 00581 dm->getVertNo(dm, mface->v3, data[2]); 00582 } else { 00583 dm->getVertCo(dm, mface->v1, data[0]); 00584 dm->getVertCo(dm, mface->v2, data[1]); 00585 dm->getVertCo(dm, mface->v3, data[2]); 00586 } 00587 00588 interp_barycentric_tri_data(data, u, v, res); 00589 } 00590 00591 static void *init_heights_data(MultiresBakeRender *bkr, Image* ima) 00592 { 00593 MHeightBakeData *height_data; 00594 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00595 00596 height_data= MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData"); 00597 00598 height_data->ima= ima; 00599 height_data->heights= MEM_callocN(sizeof(float)*ibuf->x*ibuf->y, "MultiresBake heights"); 00600 height_data->height_max= -FLT_MAX; 00601 height_data->height_min= FLT_MAX; 00602 00603 if(!bkr->use_lores_mesh) { 00604 SubsurfModifierData smd= {{NULL}}; 00605 int ss_lvl= bkr->tot_lvl - bkr->lvl; 00606 00607 CLAMP(ss_lvl, 0, 6); 00608 00609 smd.levels= smd.renderLevels= ss_lvl; 00610 smd.flags|= eSubsurfModifierFlag_SubsurfUv; 00611 00612 if(bkr->simple) 00613 smd.subdivType= ME_SIMPLE_SUBSURF; 00614 00615 height_data->ssdm= subsurf_make_derived_from_derived(bkr->lores_dm, &smd, 0, NULL, 0, 0, 0); 00616 } 00617 00618 return (void*)height_data; 00619 } 00620 00621 static void apply_heights_data(void *bake_data) 00622 { 00623 MHeightBakeData *height_data= (MHeightBakeData*)bake_data; 00624 ImBuf *ibuf= BKE_image_get_ibuf(height_data->ima, NULL); 00625 int x, y, i; 00626 float height, *heights= height_data->heights; 00627 float min= height_data->height_min, max= height_data->height_max; 00628 00629 for(x= 0; x<ibuf->x; x++) { 00630 for(y =0; y<ibuf->y; y++) { 00631 i= ibuf->x*y + x; 00632 00633 if(((char*)ibuf->userdata)[i] != FILTER_MASK_USED) 00634 continue; 00635 00636 if(ibuf->rect_float) { 00637 float *rrgbf= ibuf->rect_float + i*4; 00638 00639 if(max-min > 1e-5) height= (heights[i]-min)/(max-min); 00640 else height= 0; 00641 00642 rrgbf[0]=rrgbf[1]=rrgbf[2]= height; 00643 } else { 00644 char *rrgb= (char*)ibuf->rect + i*4; 00645 00646 if(max-min > 1e-5) height= (heights[i]-min)/(max-min); 00647 else height= 0; 00648 00649 rrgb[0]=rrgb[1]=rrgb[2]= FTOCHAR(height); 00650 } 00651 } 00652 } 00653 00654 ibuf->userflags= IB_RECT_INVALID; 00655 } 00656 00657 static void free_heights_data(void *bake_data) 00658 { 00659 MHeightBakeData *height_data= (MHeightBakeData*)bake_data; 00660 00661 if(height_data->ssdm) 00662 height_data->ssdm->release(height_data->ssdm); 00663 00664 MEM_freeN(height_data->heights); 00665 MEM_freeN(height_data); 00666 } 00667 00668 /* MultiresBake callback for heights baking 00669 general idea: 00670 - find coord of point with specified UV in hi-res mesh (let's call it p1) 00671 - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res 00672 mesh to make texture smoother) let's call this point p0 and n. 00673 - height wound be dot(n, p1-p0) */ 00674 static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, 00675 const int face_index, const int lvl, const float st[2], 00676 float UNUSED(tangmat[3][3]), const int x, const int y) 00677 { 00678 MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); 00679 MFace mface; 00680 Image *ima= mtface[face_index].tpage; 00681 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00682 MHeightBakeData *height_data= (MHeightBakeData*)bake_data; 00683 float uv[2], *st0, *st1, *st2, *st3; 00684 int pixel= ibuf->x*y + x; 00685 float vec[3], p0[3], p1[3], n[3], len; 00686 00687 lores_dm->getFace(lores_dm, face_index, &mface); 00688 00689 st0= mtface[face_index].uv[0]; 00690 st1= mtface[face_index].uv[1]; 00691 st2= mtface[face_index].uv[2]; 00692 00693 if(mface.v4) { 00694 st3= mtface[face_index].uv[3]; 00695 resolve_quad_uv(uv, st, st0, st1, st2, st3); 00696 } else 00697 resolve_tri_uv(uv, st, st0, st1, st2); 00698 00699 CLAMP(uv[0], 0.0f, 1.0f); 00700 CLAMP(uv[1], 0.0f, 1.0f); 00701 00702 get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], p1, 0); 00703 00704 if(height_data->ssdm) { 00705 //get_ccgdm_data_ss(lores_dm, height_data->ssdm, lvl, face_index, uv[0], uv[1], p0, n); 00706 get_ccgdm_data(lores_dm, height_data->ssdm, 0, face_index, uv[0], uv[1], p0, n); 00707 } else { 00708 MFace mface; 00709 lores_dm->getFace(lores_dm, face_index, &mface); 00710 00711 if(mface.v4) { 00712 interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); 00713 interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); 00714 } else { 00715 interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); 00716 interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); 00717 } 00718 } 00719 00720 sub_v3_v3v3(vec, p1, p0); 00721 //len= len_v3(vec); 00722 len= dot_v3v3(n, vec); 00723 00724 height_data->heights[pixel]= len; 00725 if(len<height_data->height_min) height_data->height_min= len; 00726 if(len>height_data->height_max) height_data->height_max= len; 00727 00728 if(ibuf->rect_float) { 00729 float *rrgbf= ibuf->rect_float + pixel*4; 00730 rrgbf[3]= 1.0f; 00731 00732 ibuf->userflags= IB_RECT_INVALID; 00733 } else { 00734 char *rrgb= (char*)ibuf->rect + pixel*4; 00735 rrgb[3]= 255; 00736 } 00737 } 00738 00739 /* MultiresBake callback for normals' baking 00740 general idea: 00741 - find coord and normal of point with specified UV in hi-res mesh 00742 - multiply it by tangmat 00743 - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ 00744 static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *UNUSED(bake_data), 00745 const int face_index, const int lvl, const float st[2], 00746 float tangmat[3][3], const int x, const int y) 00747 { 00748 MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); 00749 MFace mface; 00750 Image *ima= mtface[face_index].tpage; 00751 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00752 float uv[2], *st0, *st1, *st2, *st3; 00753 int pixel= ibuf->x*y + x; 00754 float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5}; 00755 00756 lores_dm->getFace(lores_dm, face_index, &mface); 00757 00758 st0= mtface[face_index].uv[0]; 00759 st1= mtface[face_index].uv[1]; 00760 st2= mtface[face_index].uv[2]; 00761 00762 if(mface.v4) { 00763 st3= mtface[face_index].uv[3]; 00764 resolve_quad_uv(uv, st, st0, st1, st2, st3); 00765 } else 00766 resolve_tri_uv(uv, st, st0, st1, st2); 00767 00768 CLAMP(uv[0], 0.0f, 1.0f); 00769 CLAMP(uv[1], 0.0f, 1.0f); 00770 00771 get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], NULL, n); 00772 00773 mul_v3_m3v3(vec, tangmat, n); 00774 normalize_v3(vec); 00775 mul_v3_fl(vec, 0.5); 00776 add_v3_v3(vec, tmp); 00777 00778 if(ibuf->rect_float) { 00779 float *rrgbf= ibuf->rect_float + pixel*4; 00780 rrgbf[0]= vec[0]; 00781 rrgbf[1]= vec[1]; 00782 rrgbf[2]= vec[2]; 00783 rrgbf[3]= 1.0f; 00784 00785 ibuf->userflags= IB_RECT_INVALID; 00786 } else { 00787 char *rrgb= (char*)ibuf->rect + pixel*4; 00788 rrgb[0]= FTOCHAR(vec[0]); 00789 rrgb[1]= FTOCHAR(vec[1]); 00790 rrgb[2]= FTOCHAR(vec[2]); 00791 rrgb[3]= 255; 00792 } 00793 } 00794 00795 static void count_images(MultiresBakeRender *bkr) 00796 { 00797 int a, totface; 00798 DerivedMesh *dm= bkr->lores_dm; 00799 MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE); 00800 00801 bkr->image.first= bkr->image.last= NULL; 00802 bkr->tot_image= 0; 00803 00804 totface= dm->getNumFaces(dm); 00805 00806 for(a= 0; a<totface; a++) 00807 mtface[a].tpage->id.flag&= ~LIB_DOIT; 00808 00809 for(a= 0; a<totface; a++) { 00810 Image *ima= mtface[a].tpage; 00811 if((ima->id.flag&LIB_DOIT)==0) { 00812 LinkData *data= BLI_genericNodeN(ima); 00813 BLI_addtail(&bkr->image, data); 00814 bkr->tot_image++; 00815 ima->id.flag|= LIB_DOIT; 00816 } 00817 } 00818 00819 for(a= 0; a<totface; a++) 00820 mtface[a].tpage->id.flag&= ~LIB_DOIT; 00821 } 00822 00823 static void bake_images(MultiresBakeRender *bkr) 00824 { 00825 LinkData *link; 00826 00827 for(link= bkr->image.first; link; link= link->next) { 00828 Image *ima= (Image*)link->data; 00829 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00830 00831 if(ibuf->x>0 && ibuf->y>0) { 00832 ibuf->userdata= MEM_callocN(ibuf->y*ibuf->x, "MultiresBake imbuf mask"); 00833 00834 switch(bkr->mode) { 00835 case RE_BAKE_NORMALS: 00836 do_multires_bake(bkr, ima, apply_tangmat_callback, NULL, NULL, NULL); 00837 break; 00838 case RE_BAKE_DISPLACEMENT: 00839 do_multires_bake(bkr, ima, apply_heights_callback, init_heights_data, 00840 apply_heights_data, free_heights_data); 00841 break; 00842 } 00843 } 00844 00845 ima->id.flag|= LIB_DOIT; 00846 } 00847 } 00848 00849 static void finish_images(MultiresBakeRender *bkr) 00850 { 00851 LinkData *link; 00852 00853 for(link= bkr->image.first; link; link= link->next) { 00854 Image *ima= (Image*)link->data; 00855 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00856 00857 if(ibuf->x<=0 || ibuf->y<=0) 00858 continue; 00859 00860 RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, bkr->bake_filter); 00861 00862 ibuf->userflags|= IB_BITMAPDIRTY; 00863 00864 if(ibuf->rect_float) 00865 ibuf->userflags|= IB_RECT_INVALID; 00866 00867 if(ibuf->mipmap[0]) { 00868 ibuf->userflags|= IB_MIPMAP_INVALID; 00869 imb_freemipmapImBuf(ibuf); 00870 } 00871 00872 if(ibuf->userdata) { 00873 MEM_freeN(ibuf->userdata); 00874 ibuf->userdata= NULL; 00875 } 00876 } 00877 } 00878 00879 static void multiresbake_start(MultiresBakeRender *bkr) 00880 { 00881 count_images(bkr); 00882 bake_images(bkr); 00883 finish_images(bkr); 00884 } 00885 00886 static int multiresbake_check(bContext *C, wmOperator *op) { 00887 Scene *scene= CTX_data_scene(C); 00888 Object *ob; 00889 Mesh *me; 00890 MultiresModifierData *mmd; 00891 int ok= 1, a; 00892 00893 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { 00894 ob= base->object; 00895 00896 if(ob->type != OB_MESH) { 00897 BKE_report(op->reports, RPT_ERROR, "Basking of multires data only works with active object which is a mesh"); 00898 00899 ok= 0; 00900 break; 00901 } 00902 00903 me= (Mesh*)ob->data; 00904 mmd= get_multires_modifier(scene, ob, 0); 00905 00906 /* Multi-resolution should be and be last in the stack */ 00907 if(ok && mmd) { 00908 ModifierData *md; 00909 00910 ok= mmd->totlvl>0; 00911 00912 for(md = (ModifierData*)mmd->modifier.next; md && ok; md = md->next) { 00913 if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { 00914 ok= 0; 00915 } 00916 } 00917 } else ok= 0; 00918 00919 if(!ok) { 00920 BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object"); 00921 00922 break; 00923 } 00924 00925 if(!me->mtface) { 00926 BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking"); 00927 00928 ok= 0; 00929 } else { 00930 a= me->totface; 00931 while (ok && a--) { 00932 Image *ima= me->mtface[a].tpage; 00933 00934 if(!ima) { 00935 BKE_report(op->reports, RPT_ERROR, "You should have active texture to use multires baker"); 00936 00937 ok= 0; 00938 } else { 00939 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 00940 00941 if(!ibuf) { 00942 BKE_report(op->reports, RPT_ERROR, "Baking should happend to image with image buffer"); 00943 00944 ok= 0; 00945 } else { 00946 if(ibuf->rect==NULL && ibuf->rect_float==NULL) 00947 ok= 0; 00948 00949 if(ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4)) 00950 ok= 0; 00951 00952 if(!ok) 00953 BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type"); 00954 } 00955 } 00956 } 00957 } 00958 00959 if(!ok) 00960 break; 00961 } 00962 CTX_DATA_END; 00963 00964 return ok; 00965 } 00966 00967 static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *lvl) 00968 { 00969 DerivedMesh *dm; 00970 MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0); 00971 Mesh *me= (Mesh*)ob->data; 00972 00973 if(ob->mode==OB_MODE_SCULPT) *lvl= mmd->sculptlvl; 00974 else *lvl= mmd->lvl; 00975 00976 if(*lvl==0) { 00977 DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob); 00978 dm= CDDM_copy(tmp_dm); 00979 tmp_dm->release(tmp_dm); 00980 } else { 00981 MultiresModifierData tmp_mmd= *mmd; 00982 DerivedMesh *cddm= CDDM_from_mesh(me, ob); 00983 00984 tmp_mmd.lvl= *lvl; 00985 dm= multires_dm_create_from_derived(&tmp_mmd, 1, cddm, ob, 0, 0); 00986 cddm->release(cddm); 00987 } 00988 00989 return dm; 00990 } 00991 00992 static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *lvl, int *simple) 00993 { 00994 Mesh *me= (Mesh*)ob->data; 00995 MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0); 00996 MultiresModifierData tmp_mmd= *mmd; 00997 DerivedMesh *cddm= CDDM_from_mesh(me, ob); 00998 DerivedMesh *dm; 00999 01000 *lvl= mmd->totlvl; 01001 *simple= mmd->simple; 01002 01003 tmp_mmd.lvl= mmd->totlvl; 01004 dm= multires_dm_create_from_derived(&tmp_mmd, 1, cddm, ob, 0, 0); 01005 cddm->release(cddm); 01006 01007 return dm; 01008 } 01009 01010 static void clear_images(MTFace *mtface, int totface) 01011 { 01012 int a; 01013 const float vec_alpha[4]= {0.0f, 0.0f, 0.0f, 0.0f}; 01014 const float vec_solid[4]= {0.0f, 0.0f, 0.0f, 1.0f}; 01015 01016 for(a= 0; a<totface; a++) 01017 mtface[a].tpage->id.flag&= ~LIB_DOIT; 01018 01019 for(a= 0; a<totface; a++) { 01020 Image *ima= mtface[a].tpage; 01021 01022 if((ima->id.flag&LIB_DOIT)==0) { 01023 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01024 01025 IMB_rectfill(ibuf, (ibuf->depth == 32) ? vec_alpha : vec_solid); 01026 ima->id.flag|= LIB_DOIT; 01027 } 01028 } 01029 01030 for(a= 0; a<totface; a++) 01031 mtface[a].tpage->id.flag&= ~LIB_DOIT; 01032 } 01033 01034 static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) 01035 { 01036 Object *ob; 01037 Scene *scene= CTX_data_scene(C); 01038 01039 if(!multiresbake_check(C, op)) 01040 return OPERATOR_CANCELLED; 01041 01042 if(scene->r.bake_flag&R_BAKE_CLEAR) { /* clear images */ 01043 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { 01044 Mesh *me; 01045 01046 ob= base->object; 01047 me= (Mesh*)ob->data; 01048 01049 clear_images(me->mtface, me->totface); 01050 } 01051 CTX_DATA_END; 01052 } 01053 01054 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { 01055 MultiresBakeRender bkr= {0}; 01056 01057 ob= base->object; 01058 01059 /* copy data stored in job descriptor */ 01060 bkr.bake_filter= scene->r.bake_filter; 01061 bkr.mode= scene->r.bake_mode; 01062 bkr.use_lores_mesh= scene->r.bake_flag&R_BAKE_LORES_MESH; 01063 01064 /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ 01065 bkr.lores_dm= multiresbake_create_loresdm(scene, ob, &bkr.lvl); 01066 bkr.hires_dm= multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple); 01067 01068 multiresbake_start(&bkr); 01069 01070 BLI_freelistN(&bkr.image); 01071 01072 bkr.lores_dm->release(bkr.lores_dm); 01073 bkr.hires_dm->release(bkr.hires_dm); 01074 } 01075 CTX_DATA_END; 01076 01077 return OPERATOR_FINISHED; 01078 } 01079 01080 /* Multiresbake adopted for job-system executing */ 01081 static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) 01082 { 01083 Scene *scene= CTX_data_scene(C); 01084 Object *ob; 01085 01086 /* backup scene settings, so their changing in UI would take no effect on baker */ 01087 bkj->bake_filter= scene->r.bake_filter; 01088 bkj->mode= scene->r.bake_mode; 01089 bkj->use_lores_mesh= scene->r.bake_flag&R_BAKE_LORES_MESH; 01090 bkj->bake_clear= scene->r.bake_flag&R_BAKE_CLEAR; 01091 01092 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { 01093 MultiresBakerJobData *data; 01094 ob= base->object; 01095 01096 data= MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data"); 01097 data->lores_dm = multiresbake_create_loresdm(scene, ob, &data->lvl); 01098 data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple); 01099 BLI_addtail(&bkj->data, data); 01100 } 01101 CTX_DATA_END; 01102 } 01103 01104 static void multiresbake_startjob(void *bkv, short *stop, short *do_update, float *progress) 01105 { 01106 MultiresBakerJobData *data; 01107 MultiresBakeJob *bkj= bkv; 01108 int baked_objects= 0, tot_obj; 01109 01110 tot_obj= BLI_countlist(&bkj->data); 01111 01112 if(bkj->bake_clear) { /* clear images */ 01113 for(data= bkj->data.first; data; data= data->next) { 01114 DerivedMesh *dm= data->lores_dm; 01115 MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE); 01116 01117 clear_images(mtface, dm->getNumFaces(dm)); 01118 } 01119 } 01120 01121 for(data= bkj->data.first; data; data= data->next) { 01122 MultiresBakeRender bkr= {0}; 01123 01124 /* copy data stored in job descriptor */ 01125 bkr.bake_filter= bkj->bake_filter; 01126 bkr.mode= bkj->mode; 01127 bkr.use_lores_mesh= bkj->use_lores_mesh; 01128 01129 /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ 01130 bkr.lores_dm= data->lores_dm; 01131 bkr.hires_dm= data->hires_dm; 01132 bkr.tot_lvl= data->tot_lvl; 01133 bkr.lvl= data->lvl; 01134 bkr.simple= data->simple; 01135 01136 /* needed for proper progress bar */ 01137 bkr.tot_obj= tot_obj; 01138 bkr.baked_objects= baked_objects; 01139 01140 bkr.stop= stop; 01141 bkr.do_update= do_update; 01142 bkr.progress= progress; 01143 01144 multiresbake_start(&bkr); 01145 01146 BLI_freelistN(&bkr.image); 01147 01148 baked_objects++; 01149 } 01150 } 01151 01152 static void multiresbake_freejob(void *bkv) 01153 { 01154 MultiresBakeJob *bkj= bkv; 01155 MultiresBakerJobData *data, *next; 01156 01157 data= bkj->data.first; 01158 while (data) { 01159 next= data->next; 01160 data->lores_dm->release(data->lores_dm); 01161 data->hires_dm->release(data->hires_dm); 01162 MEM_freeN(data); 01163 data= next; 01164 } 01165 01166 MEM_freeN(bkj); 01167 } 01168 01169 static int multiresbake_image_exec(bContext *C, wmOperator *op) 01170 { 01171 Scene *scene= CTX_data_scene(C); 01172 MultiresBakeJob *bkr; 01173 wmJob *steve; 01174 01175 if(!multiresbake_check(C, op)) 01176 return OPERATOR_CANCELLED; 01177 01178 bkr= MEM_callocN(sizeof(MultiresBakeJob), "MultiresBakeJob data"); 01179 init_multiresbake_job(C, bkr); 01180 01181 /* setup job */ 01182 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Multires Bake", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS); 01183 WM_jobs_customdata(steve, bkr, multiresbake_freejob); 01184 WM_jobs_timer(steve, 0.2, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ 01185 WM_jobs_callbacks(steve, multiresbake_startjob, NULL, NULL, NULL); 01186 01187 G.afbreek= 0; 01188 01189 WM_jobs_start(CTX_wm_manager(C), steve); 01190 WM_cursor_wait(0); 01191 01192 /* add modal handler for ESC */ 01193 WM_event_add_modal_handler(C, op); 01194 01195 return OPERATOR_RUNNING_MODAL; 01196 } 01197 01198 /* ****************** render BAKING ********************** */ 01199 01200 /* threaded break test */ 01201 static int thread_break(void *UNUSED(arg)) 01202 { 01203 return G.afbreek; 01204 } 01205 01206 static ScrArea *biggest_image_area(bScreen *screen) 01207 { 01208 ScrArea *sa, *big= NULL; 01209 int size, maxsize= 0; 01210 01211 for(sa= screen->areabase.first; sa; sa= sa->next) { 01212 if(sa->spacetype==SPACE_IMAGE) { 01213 size= sa->winx*sa->winy; 01214 if(sa->winx > 10 && sa->winy > 10 && size > maxsize) { 01215 maxsize= size; 01216 big= sa; 01217 } 01218 } 01219 } 01220 return big; 01221 } 01222 01223 01224 typedef struct BakeRender { 01225 Render *re; 01226 Main *main; 01227 Scene *scene; 01228 struct Object *actob; 01229 int tot, ready; 01230 01231 ReportList *reports; 01232 01233 short *stop; 01234 short *do_update; 01235 float *progress; 01236 01237 ListBase threads; 01238 01239 /* backup */ 01240 short prev_wo_amb_occ; 01241 short prev_r_raytrace; 01242 01243 /* for redrawing */ 01244 ScrArea *sa; 01245 } BakeRender; 01246 01247 /* use by exec and invoke */ 01248 static int test_bake_internal(bContext *C, ReportList *reports) 01249 { 01250 Scene *scene= CTX_data_scene(C); 01251 01252 if(scene->r.renderer!=R_INTERN) { 01253 BKE_report(reports, RPT_ERROR, "Bake only supported for Internal Renderer"); 01254 } else if((scene->r.bake_flag & R_BAKE_TO_ACTIVE) && CTX_data_active_object(C)==NULL) { 01255 BKE_report(reports, RPT_ERROR, "No active object"); 01256 } 01257 else if(scene->r.bake_mode==RE_BAKE_AO && scene->world==NULL) { 01258 BKE_report(reports, RPT_ERROR, "No world set up"); 01259 } 01260 else { 01261 return 1; 01262 } 01263 01264 return 0; 01265 } 01266 01267 static void init_bake_internal(BakeRender *bkr, bContext *C) 01268 { 01269 Scene *scene= CTX_data_scene(C); 01270 01271 /* get editmode results */ 01272 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */ 01273 01274 bkr->sa= biggest_image_area(CTX_wm_screen(C)); /* can be NULL */ 01275 bkr->main= CTX_data_main(C); 01276 bkr->scene= scene; 01277 bkr->actob= (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL; 01278 bkr->re= RE_NewRender("_Bake View_"); 01279 01280 if(scene->r.bake_mode==RE_BAKE_AO) { 01281 /* If raytracing or AO is disabled, switch it on temporarily for baking. */ 01282 bkr->prev_wo_amb_occ = (scene->world->mode & WO_AMB_OCC) != 0; 01283 scene->world->mode |= WO_AMB_OCC; 01284 } 01285 if(scene->r.bake_mode==RE_BAKE_AO || bkr->actob) { 01286 bkr->prev_r_raytrace = (scene->r.mode & R_RAYTRACE) != 0; 01287 scene->r.mode |= R_RAYTRACE; 01288 } 01289 } 01290 01291 static void finish_bake_internal(BakeRender *bkr) 01292 { 01293 RE_Database_Free(bkr->re); 01294 01295 /* restore raytrace and AO */ 01296 if(bkr->scene->r.bake_mode==RE_BAKE_AO) 01297 if(bkr->prev_wo_amb_occ == 0) 01298 bkr->scene->world->mode &= ~WO_AMB_OCC; 01299 01300 if(bkr->scene->r.bake_mode==RE_BAKE_AO || bkr->actob) 01301 if(bkr->prev_r_raytrace == 0) 01302 bkr->scene->r.mode &= ~R_RAYTRACE; 01303 01304 if(bkr->tot) { 01305 Image *ima; 01306 /* force OpenGL reload and mipmap recalc */ 01307 for(ima= G.main->image.first; ima; ima= ima->id.next) { 01308 if(ima->ok==IMA_OK_LOADED) { 01309 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01310 if(ibuf) { 01311 if(ibuf->userflags & IB_BITMAPDIRTY) { 01312 GPU_free_image(ima); 01313 imb_freemipmapImBuf(ibuf); 01314 } 01315 01316 /* freed when baking is done, but if its canceled we need to free here */ 01317 if (ibuf->userdata) { 01318 MEM_freeN(ibuf->userdata); 01319 ibuf->userdata= NULL; 01320 } 01321 } 01322 } 01323 } 01324 } 01325 } 01326 01327 static void *do_bake_render(void *bake_v) 01328 { 01329 BakeRender *bkr= bake_v; 01330 01331 bkr->tot= RE_bake_shade_all_selected(bkr->re, bkr->scene->r.bake_mode, bkr->actob, NULL, bkr->progress); 01332 bkr->ready= 1; 01333 01334 return NULL; 01335 } 01336 01337 static void bake_startjob(void *bkv, short *stop, short *do_update, float *progress) 01338 { 01339 BakeRender *bkr= bkv; 01340 Scene *scene= bkr->scene; 01341 Main *bmain= bkr->main; 01342 01343 bkr->stop= stop; 01344 bkr->do_update= do_update; 01345 bkr->progress= progress; 01346 01347 RE_test_break_cb(bkr->re, NULL, thread_break); 01348 G.afbreek= 0; /* blender_test_break uses this global */ 01349 01350 RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob); 01351 01352 /* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */ 01353 bkr->tot= RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress); 01354 } 01355 01356 static void bake_update(void *bkv) 01357 { 01358 BakeRender *bkr= bkv; 01359 01360 if(bkr->sa && bkr->sa->spacetype==SPACE_IMAGE) { /* incase the user changed while baking */ 01361 SpaceImage *sima= bkr->sa->spacedata.first; 01362 if(sima) 01363 sima->image= RE_bake_shade_get_image(); 01364 } 01365 } 01366 01367 static void bake_freejob(void *bkv) 01368 { 01369 BakeRender *bkr= bkv; 01370 finish_bake_internal(bkr); 01371 01372 if(bkr->tot==0) BKE_report(bkr->reports, RPT_ERROR, "No objects or images found to bake to"); 01373 MEM_freeN(bkr); 01374 G.rendering = 0; 01375 } 01376 01377 /* catch esc */ 01378 static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event) 01379 { 01380 /* no running blender, remove handler and pass through */ 01381 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) 01382 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; 01383 01384 /* running render */ 01385 switch (event->type) { 01386 case ESCKEY: 01387 return OPERATOR_RUNNING_MODAL; 01388 break; 01389 } 01390 return OPERATOR_PASS_THROUGH; 01391 } 01392 01393 static int is_multires_bake(Scene *scene) 01394 { 01395 if ( ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT)) 01396 return scene->r.bake_flag & R_BAKE_MULTIRES; 01397 01398 return 0; 01399 } 01400 01401 static int objects_bake_render_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(_event)) 01402 { 01403 Scene *scene= CTX_data_scene(C); 01404 int result= OPERATOR_CANCELLED; 01405 01406 if(is_multires_bake(scene)) { 01407 result= multiresbake_image_exec(C, op); 01408 } else { 01409 /* only one render job at a time */ 01410 if(WM_jobs_test(CTX_wm_manager(C), scene)) 01411 return OPERATOR_CANCELLED; 01412 01413 if(test_bake_internal(C, op->reports)==0) { 01414 return OPERATOR_CANCELLED; 01415 } 01416 else { 01417 BakeRender *bkr= MEM_callocN(sizeof(BakeRender), "render bake"); 01418 wmJob *steve; 01419 01420 init_bake_internal(bkr, C); 01421 bkr->reports= op->reports; 01422 01423 /* setup job */ 01424 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS); 01425 WM_jobs_customdata(steve, bkr, bake_freejob); 01426 WM_jobs_timer(steve, 0.2, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ 01427 WM_jobs_callbacks(steve, bake_startjob, NULL, bake_update, NULL); 01428 01429 G.afbreek= 0; 01430 G.rendering = 1; 01431 01432 WM_jobs_start(CTX_wm_manager(C), steve); 01433 01434 WM_cursor_wait(0); 01435 01436 /* add modal handler for ESC */ 01437 WM_event_add_modal_handler(C, op); 01438 } 01439 01440 result= OPERATOR_RUNNING_MODAL; 01441 } 01442 01443 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); 01444 01445 return result; 01446 } 01447 01448 01449 static int bake_image_exec(bContext *C, wmOperator *op) 01450 { 01451 Main *bmain= CTX_data_main(C); 01452 Scene *scene= CTX_data_scene(C); 01453 int result= OPERATOR_CANCELLED; 01454 01455 if(is_multires_bake(scene)) { 01456 result= multiresbake_image_exec_locked(C, op); 01457 } else { 01458 if(test_bake_internal(C, op->reports)==0) { 01459 return OPERATOR_CANCELLED; 01460 } 01461 else { 01462 ListBase threads; 01463 BakeRender bkr= {NULL}; 01464 01465 init_bake_internal(&bkr, C); 01466 bkr.reports= op->reports; 01467 01468 RE_test_break_cb(bkr.re, NULL, thread_break); 01469 G.afbreek= 0; /* blender_test_break uses this global */ 01470 01471 RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE)? OBACT: NULL); 01472 01473 /* baking itself is threaded, cannot use test_break in threads */ 01474 BLI_init_threads(&threads, do_bake_render, 1); 01475 bkr.ready= 0; 01476 BLI_insert_thread(&threads, &bkr); 01477 01478 while(bkr.ready==0) { 01479 PIL_sleep_ms(50); 01480 if(bkr.ready) 01481 break; 01482 01483 /* used to redraw in 2.4x but this is just for exec in 2.5 */ 01484 if (!G.background) 01485 blender_test_break(); 01486 } 01487 BLI_end_threads(&threads); 01488 01489 if(bkr.tot==0) BKE_report(op->reports, RPT_ERROR, "No valid images found to bake to"); 01490 01491 finish_bake_internal(&bkr); 01492 01493 result= OPERATOR_FINISHED; 01494 } 01495 } 01496 01497 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); 01498 01499 return result; 01500 } 01501 01502 void OBJECT_OT_bake_image(wmOperatorType *ot) 01503 { 01504 /* identifiers */ 01505 ot->name= "Bake"; 01506 ot->description= "Bake image textures of selected objects"; 01507 ot->idname= "OBJECT_OT_bake_image"; 01508 01509 /* api callbacks */ 01510 ot->exec= bake_image_exec; 01511 ot->invoke= objects_bake_render_invoke; 01512 ot->modal= objects_bake_render_modal; 01513 }