static void image_mipmap_test(Tex *tex, ImBuf *ibuf) { if (tex->imaflag & TEX_MIPMAP) { if ((ibuf->flags & IB_fields) == 0) { if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) { BLI_lock_thread(LOCK_IMAGE); if (ibuf->userflags & IB_MIPMAP_INVALID) { IMB_remakemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP); ibuf->userflags &= ~IB_MIPMAP_INVALID; } BLI_unlock_thread(LOCK_IMAGE); } if (ibuf->mipmap[0] == NULL) { BLI_lock_thread(LOCK_IMAGE); if (ibuf->mipmap[0] == NULL) IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP); BLI_unlock_thread(LOCK_IMAGE); } /* if no mipmap could be made, fall back on non-mipmap render */ if (ibuf->mipmap[0] == NULL) { tex->imaflag &= ~TEX_MIPMAP; } } } }
static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted) { char name[FILE_MAX]; int quality, rectx, recty; int size = rendersize_to_number(proxy_render_size); ImBuf *scaleibuf; get_proxy_fname(clip, proxy_render_size, undistorted, cfra, name); rectx = ibuf->x * size / 100.0f; recty = ibuf->y * size / 100.0f; scaleibuf = IMB_dupImBuf(ibuf); IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty); quality = clip->proxy.quality; scaleibuf->ftype = JPG | quality; /* unsupported feature only confuses other s/w */ if (scaleibuf->planes == 32) scaleibuf->planes = 24; BLI_lock_thread(LOCK_MOVIECLIP); BLI_make_existing_file(name); if (IMB_saveiff(scaleibuf, name, IB_rect) == 0) perror(name); BLI_unlock_thread(LOCK_MOVIECLIP); IMB_freeImBuf(scaleibuf); }
void ViewerBaseOperation::initImage() { Image *anImage = this->m_image; ImBuf *ibuf = BKE_image_acquire_ibuf(anImage, this->m_imageUser, &this->m_lock); if (!ibuf) return; if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { BLI_lock_thread(LOCK_DRAW_IMAGE); imb_freerectImBuf(ibuf); imb_freerectfloatImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); ibuf->x = getWidth(); ibuf->y = getHeight(); imb_addrectImBuf(ibuf); imb_addrectfloatImBuf(ibuf); anImage->ok = IMA_OK_LOADED; BLI_unlock_thread(LOCK_DRAW_IMAGE); } /* now we combine the input with ibuf */ this->m_outputBuffer = ibuf->rect_float; this->m_outputBufferDisplay = (unsigned char *)ibuf->rect; BKE_image_release_ibuf(this->m_image, this->m_lock); }
static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *user, int flag, int postprocess_flag, int cache_flag) { ImBuf *ibuf = NULL; int framenr = user->framenr; bool need_postprocess = false; /* cache isn't threadsafe itself and also loading of movies * can't happen from concurent threads that's why we use lock here */ BLI_lock_thread(LOCK_MOVIECLIP); /* try to obtain cached postprocessed frame first */ if (need_postprocessed_frame(user, postprocess_flag)) { ibuf = get_postprocessed_cached_frame(clip, user, flag, postprocess_flag); if (!ibuf) need_postprocess = true; } if (!ibuf) ibuf = get_imbuf_cache(clip, user, flag); if (!ibuf) { bool use_sequence = false; /* undistorted proxies for movies should be read as image sequence */ use_sequence = (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) && (user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL); if (clip->source == MCLIP_SRC_SEQUENCE || use_sequence) { ibuf = movieclip_load_sequence_file(clip, user, framenr, flag); } else { ibuf = movieclip_load_movie_file(clip, user, framenr, flag); } if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) put_imbuf_cache(clip, user, ibuf, flag, true); } if (ibuf) { clip->lastframe = framenr; real_ibuf_size(clip, user, ibuf, &clip->lastsize[0], &clip->lastsize[1]); /* postprocess frame and put to cache if needed*/ if (need_postprocess) { ImBuf *tmpibuf = ibuf; ibuf = postprocess_frame(clip, user, tmpibuf, postprocess_flag); IMB_freeImBuf(tmpibuf); if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) { put_postprocessed_frame_to_cache(clip, user, ibuf, flag, postprocess_flag); } } } BLI_unlock_thread(LOCK_MOVIECLIP); return ibuf; }
/* based on settings in node, sets drawing rect info. each redraw! */ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) { uiLayout *layout; PointerRNA ptr; bNodeSocket *nsock; float dy= node->locy; int buty; /* header */ dy-= NODE_DY; /* little bit space in top */ if(node->outputs.first) dy-= NODE_DYS/2; /* output sockets */ for(nsock= node->outputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { nsock->locx= node->locx + node->width; nsock->locy= dy - NODE_DYS; dy-= NODE_DY; } } node->prvr.xmin= node->locx + NODE_DYS; node->prvr.xmax= node->locx + node->width- NODE_DYS; /* preview rect? */ if(node->flag & NODE_PREVIEW) { /* only recalculate size when there's a preview actually, otherwise we use stored result */ BLI_lock_thread(LOCK_PREVIEW); if(node->preview && node->preview->rect) { float aspect= 1.0f; if(node->preview && node->preview->xsize && node->preview->ysize) aspect= (float)node->preview->ysize/(float)node->preview->xsize; dy-= NODE_DYS/2; node->prvr.ymax= dy; if(aspect <= 1.0f) node->prvr.ymin= dy - aspect*(node->width-NODE_DY); else { float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect; /* width correction of image */ node->prvr.ymin= dy - (node->width-NODE_DY); node->prvr.xmin+= 0.5f*dx; node->prvr.xmax-= 0.5f*dx; } dy= node->prvr.ymin - NODE_DYS/2; /* make sure that maximums are bigger or equal to minimums */ if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin); if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin); }
static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname) { RenderLayer *rlp, *rl; RenderPass *rpassp; int offs, partx, party; BLI_lock_thread(LOCK_IMAGE); for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) { rl = RE_GetRenderLayer(rr, rlp->name); /* should never happen but prevents crash if it does */ BLI_assert(rl); if (UNLIKELY(rl == NULL)) { continue; } if (rrpart->crop) { /* filters add pixel extra */ offs = (rrpart->crop + rrpart->crop * rrpart->rectx); } else { offs = 0; } /* passes are allocated in sync */ for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) { const int xstride = rpassp->channels; int a; char passname[EXR_PASS_MAXNAME]; for (a = 0; a < xstride; a++) { set_pass_name(passname, rpassp->passtype, a, rpassp->view); IMB_exr_set_channel(rl->exrhandle, rlp->name, passname, xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs); } } } party = rrpart->tilerect.ymin + rrpart->crop; partx = rrpart->tilerect.xmin + rrpart->crop; for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) { rl = RE_GetRenderLayer(rr, rlp->name); /* should never happen but prevents crash if it does */ BLI_assert(rl); if (UNLIKELY(rl == NULL)) { continue; } IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname); } BLI_unlock_thread(LOCK_IMAGE); }
static void envmap_split_ima(EnvMap *env, ImBuf *ibuf) { int dx, part; /* after lock we test cube[1], if set the other thread has done it fine */ BLI_lock_thread(LOCK_IMAGE); if (env->cube[1] == NULL) { BKE_texture_envmap_free_data(env); dx = ibuf->y; dx /= 2; if (3 * dx == ibuf->x) { env->type = ENV_CUBE; env->ok = ENV_OSA; } else if (ibuf->x == ibuf->y) { env->type = ENV_PLANE; env->ok = ENV_OSA; } else { printf("Incorrect envmap size\n"); env->ok = 0; env->ima->ok = 0; } if (env->ok) { if (env->type == ENV_CUBE) { for (part = 0; part < 6; part++) { env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect | IB_rectfloat); } IMB_float_from_rect(ibuf); IMB_rectcpy(env->cube[0], ibuf, 0, 0, 0, 0, dx, dx); IMB_rectcpy(env->cube[1], ibuf, 0, 0, dx, 0, dx, dx); IMB_rectcpy(env->cube[2], ibuf, 0, 0, 2 * dx, 0, dx, dx); IMB_rectcpy(env->cube[3], ibuf, 0, 0, 0, dx, dx, dx); IMB_rectcpy(env->cube[4], ibuf, 0, 0, dx, dx, dx, dx); IMB_rectcpy(env->cube[5], ibuf, 0, 0, 2 * dx, dx, dx, dx); } else { /* ENV_PLANE */ env->cube[1] = IMB_dupImBuf(ibuf); IMB_float_from_rect(env->cube[1]); } } } BLI_unlock_thread(LOCK_IMAGE); }
void ViewerOperation::initImage() { Image *ima = this->m_image; ImageUser iuser = *this->m_imageUser; void *lock; ImBuf *ibuf; /* make sure the image has the correct number of views */ if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) { BKE_image_verify_viewer_views(this->m_rd, ima, this->m_imageUser); } BLI_lock_thread(LOCK_DRAW_IMAGE); /* local changes to the original ImageUser */ iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName); ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock); if (!ibuf) { BLI_unlock_thread(LOCK_DRAW_IMAGE); return; } if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { imb_freerectImBuf(ibuf); imb_freerectfloatImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); ibuf->x = getWidth(); ibuf->y = getHeight(); /* zero size can happen if no image buffers exist to define a sensible resolution */ if (ibuf->x > 0 && ibuf->y > 0) imb_addrectfloatImBuf(ibuf); ima->ok = IMA_OK_LOADED; ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; } if (m_doDepthBuffer) { addzbuffloatImBuf(ibuf); } /* now we combine the input with ibuf */ this->m_outputBuffer = ibuf->rect_float; /* needed for display buffer update */ this->m_ibuf = ibuf; if (m_doDepthBuffer) { this->m_depthBuffer = ibuf->zbuf_float; } BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock); BLI_unlock_thread(LOCK_DRAW_IMAGE); }
int ntreeTexExecTree( bNodeTree *nodes, TexResult *texres, float co[3], float dxt[3], float dyt[3], int osatex, const short thread, Tex *UNUSED(tex), short which_output, int cfra, int preview, ShadeInput *shi, MTex *mtex) { TexCallData data; float *nor = texres->nor; int retval = TEX_INT; bNodeThreadStack *nts = NULL; bNodeTreeExec *exec = nodes->execdata; data.co = co; data.dxt = dxt; data.dyt = dyt; data.osatex = osatex; data.target = texres; data.do_preview = preview; data.do_manage = (shi) ? shi->do_manage : true; data.thread = thread; data.which_output = which_output; data.cfra = cfra; data.mtex = mtex; data.shi = shi; /* ensure execdata is only initialized once */ if (!exec) { BLI_lock_thread(LOCK_NODES); if (!nodes->execdata) ntreeTexBeginExecTree(nodes); BLI_unlock_thread(LOCK_NODES); exec = nodes->execdata; } nts = ntreeGetThreadStack(exec, thread); ntreeExecThreadNodes(exec, nts, &data, thread); ntreeReleaseThreadStack(nts); if (texres->nor) retval |= TEX_NOR; retval |= TEX_RGB; /* confusing stuff; the texture output node sets this to NULL to indicate no normal socket was set * however, the texture code checks this for other reasons (namely, a normal is required for material) */ texres->nor = nor; return retval; }
void CompositorOperation::deinitExecution() { if (!this->m_active) return; if (!isBreaked()) { Render *re = RE_GetRender(this->m_sceneName); RenderResult *rr = RE_AcquireResultWrite(re); if (rr) { if (rr->rectf != NULL) { MEM_freeN(rr->rectf); } rr->rectf = this->m_outputBuffer; if (rr->rectz != NULL) { MEM_freeN(rr->rectz); } rr->rectz = this->m_depthBuffer; } else { if (this->m_outputBuffer) { MEM_freeN(this->m_outputBuffer); } if (this->m_depthBuffer) { MEM_freeN(this->m_depthBuffer); } } if (re) { RE_ReleaseResult(re); re = NULL; } BLI_lock_thread(LOCK_DRAW_IMAGE); BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE); BLI_unlock_thread(LOCK_DRAW_IMAGE); } else { if (this->m_outputBuffer) { MEM_freeN(this->m_outputBuffer); } if (this->m_depthBuffer) { MEM_freeN(this->m_depthBuffer); } } this->m_outputBuffer = NULL; this->m_depthBuffer = NULL; this->m_imageInput = NULL; this->m_alphaInput = NULL; this->m_depthInput = NULL; }
int runSimulationCallback(void *data, int status, int frame) { //elbeemSimulationSettings *settings = (elbeemSimulationSettings*)data; //printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG int state = 0; if(status==FLUIDSIM_CBSTATUS_NEWFRAME) { BLI_lock_thread(LOCK_CUSTOM1); globalBakeFrame = frame-1; BLI_unlock_thread(LOCK_CUSTOM1); } //if((frameCounter==3) && (!frameStop)) { frameStop=1; return 1; } BLI_lock_thread(LOCK_CUSTOM1); state = globalBakeState; BLI_unlock_thread(LOCK_CUSTOM1); if(state!=0) { return FLUIDSIM_CBRET_ABORT; } return FLUIDSIM_CBRET_CONTINUE; }
void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint) { SSSPoints *p; if (totpoint > 0) { p= MEM_callocN(sizeof(SSSPoints), "SSSPoints"); p->co= co; p->color= color; p->area= area; p->totpoint= totpoint; BLI_lock_thread(LOCK_CUSTOM1); BLI_addtail(re->sss_points, p); BLI_unlock_thread(LOCK_CUSTOM1); } }
// run simulation in seperate thread static void *fluidsimSimulateThread(void *unused) { // *ptr) { //char* fnameCfgPath = (char*)(ptr); int ret=0; ret = elbeemSimulate(); BLI_lock_thread(LOCK_CUSTOM1); if(globalBakeState==0) { if(ret==0) { // if no error, set to normal exit globalBakeState = 1; } else { // simulation failed, display error globalBakeState = -2; } } BLI_unlock_thread(LOCK_CUSTOM1); return NULL; }
/* only for Blender internal */ bool ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr) { ShaderCallData scd; /** * \note: preserve material from ShadeInput for material id, nodetree execs change it * fix for bug "[#28012] Mat ID messy with shader nodes" */ Material *mat = shi->mat; bNodeThreadStack *nts = NULL; bNodeTreeExec *exec = ntree->execdata; int compat; /* convert caller data to struct */ scd.shi = shi; scd.shr = shr; /* each material node has own local shaderesult, with optional copying */ memset(shr, 0, sizeof(ShadeResult)); /* ensure execdata is only initialized once */ if (!exec) { BLI_lock_thread(LOCK_NODES); if (!ntree->execdata) ntree->execdata = ntreeShaderBeginExecTree(ntree); BLI_unlock_thread(LOCK_NODES); exec = ntree->execdata; } nts = ntreeGetThreadStack(exec, shi->thread); compat = ntreeExecThreadNodes(exec, nts, &scd, shi->thread); ntreeReleaseThreadStack(nts); // \note: set material back to preserved material shi->mat = mat; /* better not allow negative for now */ if (shr->combined[0] < 0.0f) shr->combined[0] = 0.0f; if (shr->combined[1] < 0.0f) shr->combined[1] = 0.0f; if (shr->combined[2] < 0.0f) shr->combined[2] = 0.0f; /* if compat is zero, it has been using non-compatible nodes */ return compat; }
static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **UNUSED(in), short UNUSED(thread)) { float x = p->co[0]; float y = p->co[1]; Image *ima= (Image *)node->id; ImageUser *iuser= (ImageUser *)node->storage; if( ima ) { ImBuf *ibuf = BKE_image_get_ibuf(ima, iuser); if( ibuf ) { float xsize, ysize; float xoff, yoff; int px, py; float *result; xsize = ibuf->x / 2; ysize = ibuf->y / 2; xoff = yoff = -1; px = (int)( (x-xoff) * xsize ); py = (int)( (y-yoff) * ysize ); if( (!xsize) || (!ysize) ) return; if( !ibuf->rect_float ) { BLI_lock_thread(LOCK_IMAGE); if( !ibuf->rect_float ) IMB_float_from_rect(ibuf); BLI_unlock_thread(LOCK_IMAGE); } while( px < 0 ) px += ibuf->x; while( py < 0 ) py += ibuf->y; while( px >= ibuf->x ) px -= ibuf->x; while( py >= ibuf->y ) py -= ibuf->y; result = ibuf->rect_float + py*ibuf->x*4 + px*4; QUATCOPY( out, result ); } } }
static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, bool undistorted, bool threaded) { char name[FILE_MAX]; int quality, rectx, recty; int size = rendersize_to_number(proxy_render_size); ImBuf *scaleibuf; get_proxy_fname(clip, proxy_render_size, undistorted, cfra, name); rectx = ibuf->x * size / 100.0f; recty = ibuf->y * size / 100.0f; scaleibuf = IMB_dupImBuf(ibuf); if (threaded) IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty); else IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty); quality = clip->proxy.quality; scaleibuf->ftype = JPG | quality; /* unsupported feature only confuses other s/w */ if (scaleibuf->planes == 32) scaleibuf->planes = 24; /* TODO: currently the most weak part of multithreaded proxies, * could be solved in a way that thread only prepares memory * buffer and write to disk happens separately */ BLI_lock_thread(LOCK_MOVIECLIP); BLI_make_existing_file(name); if (IMB_saveiff(scaleibuf, name, IB_rect) == 0) perror(name); BLI_unlock_thread(LOCK_MOVIECLIP); IMB_freeImBuf(scaleibuf); }
void ViewerOperation::initImage() { Image *ima = this->m_image; void *lock; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, this->m_imageUser, &lock); if (!ibuf) return; BLI_lock_thread(LOCK_DRAW_IMAGE); if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { imb_freerectImBuf(ibuf); imb_freerectfloatImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); ibuf->x = getWidth(); ibuf->y = getHeight(); imb_addrectfloatImBuf(ibuf); ima->ok = IMA_OK_LOADED; ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; } if (m_doDepthBuffer) { addzbuffloatImBuf(ibuf); } BLI_unlock_thread(LOCK_DRAW_IMAGE); /* now we combine the input with ibuf */ this->m_outputBuffer = ibuf->rect_float; /* needed for display buffer update */ this->m_ibuf = ibuf; if (m_doDepthBuffer) { this->m_depthBuffer = ibuf->zbuf_float; } BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock); }
int fluidsimBake(bContext *C, ReportList *reports, Object *ob) { Scene *scene= CTX_data_scene(C); FILE *fileCfg; int i; Object *fsDomain = NULL; FluidsimSettings *domainSettings; Object *obit = NULL; /* object iterator */ Base *base; int origFrame = scene->r.cfra; char debugStrBuffer[256]; int dirExist = 0; int gridlevels = 0; int simAborted = 0; // was the simulation aborted by user? int doExportOnly = 0; char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY"; const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp //char *channelNames[3] = { "translation","rotation","scale" }; char *suffixConfig = "fluidsim.cfg"; char *suffixSurface = "fluidsurface"; char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings char targetDir[FILE_MAXDIR+FILE_MAXFILE]; // store & modify output settings char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking int haveSomeFluid = 0; // check if any fluid objects are set // config vars, inited before either export or run... double calcViscosity = 0.0; int noFrames; double aniFrameTime; float aniFrlen; int channelObjCount; float *bbStart = NULL; float *bbSize = NULL; float domainMat[4][4]; float invDomMat[4][4]; // channel data int allchannelSize; // fixed by no. of frames int startFrame = 1; // dont use scene->r.sfra here, always start with frame 1 // easy frame -> sim time calc float *timeAtFrame=NULL, *timeAtIndex=NULL; // domain float *channelDomainTime = NULL; float *channelDomainViscosity = NULL; float *channelDomainGravity = NULL; // objects (currently max. 256 objs) float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale float *channelObjInivel[256]; // initial velocities float *channelObjActive[256]; // obj active channel /* fluid control channels */ float *channelAttractforceStrength[256]; float *channelAttractforceRadius[256]; float *channelVelocityforceStrength[256]; float *channelVelocityforceRadius[256]; FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; if(getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); elbeemDebugOut(debugStrBuffer); } if(getenv(exportEnvStr)) { doExportOnly = atoi(getenv(exportEnvStr)); snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr); elbeemDebugOut(debugStrBuffer); } // make sure it corresponds to startFrame setting // old: noFrames = scene->r.efra - scene->r.sfra +1; noFrames = scene->r.efra - 0; if(noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings."); return 0; } /* no object pointer, find in selected ones.. */ if(!ob) { for(base=scene->base.first; base; base= base->next) { if ((base)->flag & SELECT) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); if(fluidmdtmp && (base->object->type==OB_MESH)) { if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) { ob = base->object; break; } } } } // no domains found? if(!ob) return 0; } channelObjCount = 0; for(base=scene->base.first; base; base= base->next) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); obit = base->object; if( fluidmdtmp && (obit->type==OB_MESH) && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) { channelObjCount++; } } if (channelObjCount>=255) { BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects."); return 0; } /* check if there's another domain... */ for(base=scene->base.first; base; base= base->next) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); obit = base->object; if( fluidmdtmp &&(obit->type==OB_MESH)) { if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) { if(obit != ob) { BKE_report(reports, RPT_ERROR, "There should be only one domain object."); return 0; } } } } // check if theres any fluid // abort baking if not... for(base=scene->base.first; base; base= base->next) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); obit = base->object; if( fluidmdtmp && (obit->type==OB_MESH) && ((fluidmdtmp->fss->type == OB_FLUIDSIM_FLUID) || (fluidmdtmp->fss->type == OB_FLUIDSIM_INFLOW) )) { haveSomeFluid = 1; break; } } if(!haveSomeFluid) { BKE_report(reports, RPT_ERROR, "No fluid objects in scene."); return 0; } /* these both have to be valid, otherwise we wouldnt be here */ /* dont use ob here after...*/ fsDomain = ob; fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); domainSettings = fluidmd->fss; ob = NULL; mesh = fsDomain->data; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* rough check of settings... */ if(domainSettings->previewresxyz > domainSettings->resolutionxyz) { snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz , domainSettings->resolutionxyz); elbeemDebugOut(debugStrBuffer); domainSettings->previewresxyz = domainSettings->resolutionxyz; } // set adaptive coarsening according to resolutionxyz // this should do as an approximation, with in/outflow // doing this more accurate would be overkill // perhaps add manual setting? if(domainSettings->maxRefine <0) { if(domainSettings->resolutionxyz>128) { gridlevels = 2; } else if(domainSettings->resolutionxyz>64) { gridlevels = 1; } else { gridlevels = 0; } } else { gridlevels = domainSettings->maxRefine; } snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); elbeemDebugOut(debugStrBuffer); // prepare names... strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no strcpy(targetFile, targetDir); strcat(targetFile, suffixConfig); if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file // make sure all directories exist // as the bobjs use the same dir, this only needs to be checked // for the cfg output BLI_make_existing_file(targetFile); // check selected directory // simply try to open cfg file for writing to test validity of settings fileCfg = fopen(targetFile, "w"); if(fileCfg) { dirExist = 1; fclose(fileCfg); // remove cfg dummy from directory test if(!doExportOnly) { BLI_delete(targetFile, 0,0); } } if((strlen(targetDir)<1) || (!dirExist)) { char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE]; // invalid dir, reset to current/previous strcpy(blendDir, G.sce); BLI_splitdirstring(blendDir, blendFile); if(strlen(blendFile)>6){ int len = strlen(blendFile); if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&& (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){ blendFile[len-6] = '\0'; } } // todo... strip .blend ? snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); elbeemDebugOut(debugStrBuffer); outStringsChanged=1; } // check if modified output dir is ok if(outStringsChanged) { char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256]; int selection=0; strcpy(dispmsg,"Output settings set to: '"); strcat(dispmsg, newSurfdataPath); strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); // ask user if thats what he/she wants... selection = pupmenu(dispmsg); if(selection<1) return 0; // 0 from menu, or -1 aborted strcpy(targetDir, newSurfdataPath); strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no } // -------------------------------------------------------------------------------------------- // dump data for start frame // CHECK more reasonable to number frames according to blender? // dump data for frame 0 scene->r.cfra = startFrame; ED_update_for_newframe(C, 1); // init common export vars for both file export and run for(i=0; i<256; i++) { channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL; channelObjInivel[i] = NULL; channelObjActive[i] = NULL; channelAttractforceStrength[i] = NULL; channelAttractforceRadius[i] = NULL; channelVelocityforceStrength[i] = NULL; channelVelocityforceRadius[i] = NULL; } allchannelSize = scene->r.efra; // always use till last frame aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; // blender specific - scale according to map old/new settings in anim panel: aniFrlen = scene->r.framelen; if(domainSettings->viscosityMode==1) { /* manual mode, visc=value/(10^-vexp) */ calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue; } else { calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ]; } bbStart = domainSettings->bbStart; bbSize = domainSettings->bbSize; // always init { int timeIcu[1] = { FLUIDSIM_TIME }; float timeDef[1] = { 1. }; int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z }; float gravDef[3]; int viscIcu[1] = { FLUIDSIM_VISC }; float viscDef[1] = { 1. }; gravDef[0] = domainSettings->gravx; gravDef[1] = domainSettings->gravy; gravDef[2] = domainSettings->gravz; // time channel is a bit special, init by hand... timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex"); for(i=0; i<=scene->r.efra; i++) { timeAtIndex[i] = (float)(i-startFrame); } fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB // time channel is a multiplicator for aniFrameTime if(channelDomainTime) { for(i=0; i<allchannelSize; i++) { channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.; } } timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe"); timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1 if(channelDomainTime) { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0]; } } else { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; } } fluidsimInitChannel(scene, &channelDomainViscosity, allchannelSize, timeAtFrame, viscIcu,viscDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB if(channelDomainViscosity) { for(i=0; i<allchannelSize; i++) { channelDomainViscosity[i*2+0] = calcViscosity * channelDomainViscosity[i*2+0]; } } fluidsimInitChannel(scene, &channelDomainGravity, allchannelSize, timeAtFrame, gravIcu,gravDef, domainSettings->ipo, CHANNEL_VEC ); } // domain channel init // init obj movement channels channelObjCount=0; for(base=scene->base.first; base; base= base->next) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); obit = base->object; if( fluidmdtmp && (obit->type==OB_MESH) && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) { // cant use fluidsimInitChannel for obj channels right now, due // to the special DXXX channels, and the rotation specialities IpoCurve *icuex[3][3]; //IpoCurve *par_icuex[3][3]; #if 0 int icuIds[3][3] = { {OB_LOC_X, OB_LOC_Y, OB_LOC_Z}, {OB_ROT_X, OB_ROT_Y, OB_ROT_Z}, {OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z} }; int icudIds[3][3] = { {OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z}, {OB_DROT_X, OB_DROT_Y, OB_DROT_Z}, {OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z} }; #endif // relative ipos IpoCurve *icudex[3][3]; //IpoCurve *par_icudex[3][3]; int j,k; float vals[3] = {0.0,0.0,0.0}; int o = channelObjCount; int inivelIcu[3] = { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z }; float inivelDefs[3]; int activeIcu[1] = { FLUIDSIM_ACTIVE }; float activeDefs[1] = { 1 }; // default to on inivelDefs[0] = fluidmdtmp->fss->iniVelx; inivelDefs[1] = fluidmdtmp->fss->iniVely; inivelDefs[2] = fluidmdtmp->fss->iniVelz; // check & init loc,rot,size for(j=0; j<3; j++) { for(k=0; k<3; k++) { // XXX prevent invalid memory access until this works icuex[j][k]= NULL; icudex[j][k]= NULL; // XXX icuex[j][k] = find_ipocurve(obit->ipo, icuIds[j][k] ); // XXX icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] ); // XXX lines below were already disabled! //if(obit->parent) { //par_icuex[j][k] = find_ipocurve(obit->parent->ipo, icuIds[j][k] ); //par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] ); //} } } for(j=0; j<3; j++) { channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel"); for(i=1; i<=allchannelSize; i++) { for(k=0; k<3; k++) { if(icuex[j][k]) { // IPO exists, use it ... // XXX calc_icu(icuex[j][k], aniFrlen*((float)i) ); vals[k] = icuex[j][k]->curval; if(obit->parent) { // add parent transform, multiply scaling, add trafo&rot //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); //if(j==2) { vals[k] *= par_icuex[j][k]->curval; } //else { vals[k] += par_icuex[j][k]->curval; } } } else { // use defaults from static values float setval=0.0; if(j==0) { setval = obit->loc[k]; if(obit->parent){ setval += obit->parent->loc[k]; } } else if(j==1) { setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI ); if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); } } else { setval = obit->size[k]; if(obit->parent){ setval *= obit->parent->size[k]; } } vals[k] = setval; } if(icudex[j][k]) { // XXX calc_icu(icudex[j][k], aniFrlen*((float)i) ); //vals[k] += icudex[j][k]->curval; // add transform, multiply scaling, add trafo&rot if(j==2) { vals[k] *= icudex[j][k]->curval; } else { vals[k] += icudex[j][k]->curval; } if(obit->parent) { // add parent transform, multiply scaling, add trafo&rot //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); //if(j==2) { vals[k] *= par_icudex[j][k]->curval; } //else { vals[k] += par_icudex[j][k]->curval; } } } } // k for(k=0; k<3; k++) { float set = vals[k]; if(j==1) { // rot is downscaled by 10 for ipo !? set = 360.0 - (10.0*set); } channelObjMove[o][j][(i-1)*4 + k] = set; } // k channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i]; } } { int attrFSIcu[1] = { FLUIDSIM_ATTR_FORCE_STR }; int attrFRIcu[1] = { FLUIDSIM_ATTR_FORCE_RADIUS }; int velFSIcu[1] = { FLUIDSIM_VEL_FORCE_STR }; int velFRIcu[1] = { FLUIDSIM_VEL_FORCE_RADIUS }; float attrFSDefs[1]; float attrFRDefs[1]; float velFSDefs[1]; float velFRDefs[1]; attrFSDefs[0] = fluidmdtmp->fss->attractforceStrength; attrFRDefs[0] = fluidmdtmp->fss->attractforceRadius; velFSDefs[0] = fluidmdtmp->fss->velocityforceStrength; velFRDefs[0] = fluidmdtmp->fss->velocityforceRadius; fluidsimInitChannel(scene, &channelAttractforceStrength[o], allchannelSize, timeAtFrame, attrFSIcu,attrFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); fluidsimInitChannel(scene, &channelAttractforceRadius[o], allchannelSize, timeAtFrame, attrFRIcu,attrFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); fluidsimInitChannel(scene, &channelVelocityforceStrength[o], allchannelSize, timeAtFrame, velFSIcu,velFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); fluidsimInitChannel(scene, &channelVelocityforceRadius[o], allchannelSize, timeAtFrame, velFRIcu,velFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); } fluidsimInitChannel(scene, &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, fluidmdtmp->fss->ipo, CHANNEL_VEC ); fluidsimInitChannel(scene, &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); channelObjCount++; } } // init trafo matrix Mat4CpyMat4(domainMat, fsDomain->obmat); if(!Mat4Invert(invDomMat, domainMat)) { snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix."); // FIXME add fatal msg FS_FREE_CHANNELS; return 0; } // -------------------------------------------------------------------------------------------- // start writing / exporting strcpy(targetFile, targetDir); strcat(targetFile, suffixConfig); if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file // make sure these directories exist as well if(outStringsChanged) { BLI_make_existing_file(targetFile); } if(!doExportOnly) { ListBase threads; // perform simulation with El'Beem api and threads elbeemSimulationSettings fsset; elbeemResetSettings(&fsset); fsset.version = 1; // setup global settings for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i]; for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i]; // simulate with 50^3 fsset.resolutionxyz = (int)domainSettings->resolutionxyz; fsset.previewresxyz = (int)domainSettings->previewresxyz; // 10cm water domain fsset.realsize = domainSettings->realsize; fsset.viscosity = calcViscosity; // earth gravity fsset.gravity[0] = domainSettings->gravx; fsset.gravity[1] = domainSettings->gravy; fsset.gravity[2] = domainSettings->gravz; // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset.animStart = domainSettings->animStart; fsset.aniFrameTime = aniFrameTime; fsset.noOfFrames = noFrames; // is otherwise subtracted in parser strcpy(targetFile, targetDir); strcat(targetFile, suffixSurface); // defaults for compressibility and adaptive grids fsset.gstar = domainSettings->gstar; fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels fsset.generateParticles = domainSettings->generateParticles; fsset.numTracerParticles = domainSettings->generateTracers; fsset.surfaceSmoothing = domainSettings->surfaceSmoothing; fsset.surfaceSubdivs = domainSettings->surfaceSubdivs; fsset.farFieldSize = domainSettings->farFieldSize; strcpy( fsset.outputPath, targetFile); // domain channels fsset.channelSizeFrameTime = fsset.channelSizeViscosity = fsset.channelSizeGravity = allchannelSize; fsset.channelFrameTime = channelDomainTime; fsset.channelViscosity = channelDomainViscosity; fsset.channelGravity = channelDomainGravity; fsset.runsimCallback = &runSimulationCallback; fsset.runsimUserData = &fsset; if( (domainSettings->typeFlags&OB_FSBND_NOSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; else if((domainSettings->typeFlags&OB_FSBND_PARTSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; else if((domainSettings->typeFlags&OB_FSBND_FREESLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; fsset.domainobsPartslip = domainSettings->partSlipValue; fsset.generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender trafo matrix // fprintf(stderr,"elbeemInit - mpTrafo:\n"); { int j; for(i=0; i<4; i++) { for(j=0; j<4; j++) { fsset.surfaceTrafo[i*4+j] = invDomMat[j][i]; // fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) ); } } } // init solver with settings elbeemInit(); elbeemAddDomain(&fsset); // init objects channelObjCount = 0; for(base=scene->base.first; base; base= base->next) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); obit = base->object; //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG if( fluidmdtmp && // if has to match 3 places! // CHECKMATCH (obit->type==OB_MESH) && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE)) { float *verts=NULL; int *tris=NULL; int numVerts=0, numTris=0; int o = channelObjCount; int deform = (fluidmdtmp->fss->domainNovecgen); // misused value // todo - use blenderInitElbeemMesh int modifierIndex = modifiers_indexInObject(obit, (ModifierData *)fluidmdtmp); elbeemMesh fsmesh; elbeemResetMesh( &fsmesh ); fsmesh.type = fluidmdtmp->fss->type; // get name of object for debugging solver fsmesh.name = obit->id.name; initElbeemMesh(scene, obit, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); fsmesh.numVertices = numVerts; fsmesh.numTriangles = numTris; fsmesh.vertices = verts; fsmesh.triangles = tris; fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale = fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = allchannelSize; fsmesh.channelTranslation = channelObjMove[o][0]; fsmesh.channelRotation = channelObjMove[o][1]; fsmesh.channelScale = channelObjMove[o][2]; fsmesh.channelActive = channelObjActive[o]; if( (fsmesh.type == OB_FLUIDSIM_FLUID) || (fsmesh.type == OB_FLUIDSIM_INFLOW)) { fsmesh.channelInitialVel = channelObjInivel[o]; fsmesh.localInivelCoords = ((fluidmdtmp->fss->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0); } if( (fluidmdtmp->fss->typeFlags&OB_FSBND_NOSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; else if((fluidmdtmp->fss->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; else if((fluidmdtmp->fss->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; fsmesh.obstaclePartslip = fluidmdtmp->fss->partSlipValue; fsmesh.volumeInitType = fluidmdtmp->fss->volumeInitType; fsmesh.obstacleImpactFactor = fluidmdtmp->fss->surfaceSmoothing; // misused value if(fsmesh.type == OB_FLUIDSIM_CONTROL) { // control fluids will get exported as whole deform = 1; fsmesh.cpsTimeStart = fluidmdtmp->fss->cpsTimeStart; fsmesh.cpsTimeEnd = fluidmdtmp->fss->cpsTimeEnd; fsmesh.cpsQuality = fluidmdtmp->fss->cpsQuality; fsmesh.obstacleType = (fluidmdtmp->fss->flag & OB_FLUIDSIM_REVERSE); fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength = fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = allchannelSize; fsmesh.channelAttractforceStrength = channelAttractforceStrength[o]; fsmesh.channelAttractforceRadius = channelAttractforceRadius[o]; fsmesh.channelVelocityforceStrength = channelVelocityforceStrength[o]; fsmesh.channelVelocityforceRadius = channelVelocityforceRadius[o]; } else { // set channels to 0 fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius = fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL; } // animated meshes if(deform) { fsmesh.channelSizeVertices = allchannelSize; fluidsimInitMeshChannel(C, &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame, modifierIndex); scene->r.cfra = startFrame; ED_update_for_newframe(C, 1); // remove channels fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL; } elbeemAddMesh(&fsmesh); if(verts) MEM_freeN(verts); if(tris) MEM_freeN(tris); if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices); channelObjCount++; } // valid mesh } // objects //domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again // set to neutral, -1 means user abort, -2 means init error globalBakeState = 0; globalBakeFrame = 0; BLI_init_threads(&threads, fluidsimSimulateThread, 1); BLI_insert_thread(&threads, targetFile); { int done = 0; float noFramesf = (float)noFrames; float percentdone = 0.0; int lastRedraw = -1; g_break= 0; G.afbreek= 0; /* blender_test_break uses this global */ start_progress_bar(); while(done==0) { char busy_mess[80]; waitcursor(1); // lukep we add progress bar as an interim mesure percentdone = globalBakeFrame / noFramesf; sprintf(busy_mess, "baking fluids %d / %d |||", globalBakeFrame, (int) noFramesf); progress_bar(percentdone, busy_mess ); // longer delay to prevent frequent redrawing PIL_sleep_ms(2000); BLI_lock_thread(LOCK_CUSTOM1); if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort BLI_unlock_thread(LOCK_CUSTOM1); if (!G.background) { g_break= blender_test_break(); if(g_break) { // abort... BLI_lock_thread(LOCK_CUSTOM1); if(domainSettings) domainSettings->lastgoodframe = startFrame+globalBakeFrame; done = -1; globalBakeFrame = 0; globalBakeState = -1; simAborted = 1; BLI_unlock_thread(LOCK_CUSTOM1); break; } } // redraw the 3D for showing progress once in a while... if(lastRedraw!=globalBakeFrame) { #if 0 ScrArea *sa; scene->r.cfra = startFrame+globalBakeFrame; lastRedraw = globalBakeFrame; ED_update_for_newframe(C, 1); sa= G.curscreen->areabase.first; while(sa) { if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); } sa= sa->next; } screen_swapbuffers(); #endif } // redraw } end_progress_bar(); } BLI_end_threads(&threads); } // El'Beem API init, thread creation // -------------------------------------------------------------------------------------------- else { // write config file to be run with command line simulator BKE_report(reports, RPT_WARNING, "Config file export not supported."); } // config file export done! // -------------------------------------------------------------------------------------------- FS_FREE_CHANNELS; // go back to "current" blender time waitcursor(0); if(globalBakeState >= 0) { if(domainSettings) domainSettings->lastgoodframe = startFrame+globalBakeFrame; } scene->r.cfra = origFrame; ED_update_for_newframe(C, 1); if(!simAborted) { char elbeemerr[256]; // check if some error occurred if(globalBakeState==-2) { elbeemGetErrorString(elbeemerr); BKE_reportf(reports, RPT_ERROR, "Failed to initialize [Msg: %s]", elbeemerr); return 0; } // init error } // elbeemFree(); return 1; }
void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) { RNG *rng; int i, j, ii; BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); o->_M = M; o->_N = N; o->_V = V; o->_l = l; o->_A = A; o->_w = w; o->_damp_reflections = 1.0f - damp; o->_wind_alignment = alignment; o->_depth = depth; o->_Lx = Lx; o->_Lz = Lz; o->_wx = cos(w); o->_wz = -sin(w); /* wave direction */ o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */ o->time = time; o->_do_disp_y = do_height_field; o->_do_normals = do_normals; o->_do_chop = do_chop; o->_do_jacobian = do_jacobian; o->_k = (float *) MEM_mallocN(M * (1 + N / 2) * sizeof(float), "ocean_k"); o->_h0 = (fftw_complex *) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0"); o->_h0_minus = (fftw_complex *) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus"); o->_kx = (float *) MEM_mallocN(o->_M * sizeof(float), "ocean_kx"); o->_kz = (float *) MEM_mallocN(o->_N * sizeof(float), "ocean_kz"); /* make this robust in the face of erroneous usage */ if (o->_Lx == 0.0f) o->_Lx = 0.001f; if (o->_Lz == 0.0f) o->_Lz = 0.001f; /* the +ve components and DC */ for (i = 0; i <= o->_M / 2; ++i) o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx; /* the -ve components */ for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii) o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx; /* the +ve components and DC */ for (i = 0; i <= o->_N / 2; ++i) o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz; /* the -ve components */ for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii) o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz; /* pre-calculate the k matrix */ for (i = 0; i < o->_M; ++i) for (j = 0; j <= o->_N / 2; ++j) o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]); /*srand(seed);*/ rng = BLI_rng_new(seed); for (i = 0; i < o->_M; ++i) { for (j = 0; j < o->_N; ++j) { float r1 = gaussRand(rng); float r2 = gaussRand(rng); fftw_complex r1r2; init_complex(r1r2, r1, r2); mul_complex_f(o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); mul_complex_f(o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); } } o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); BLI_lock_thread(LOCK_FFTW); if (o->_do_disp_y) { o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE); } if (o->_do_normals) { o->_fft_in_nx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nx"); o->_fft_in_nz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nz"); o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */ o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE); } if (o->_do_chop) { o->_fft_in_x = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x"); o->_fft_in_z = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z"); o->_disp_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); o->_disp_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE); o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE); } if (o->_do_jacobian) { o->_fft_in_jxx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxx"); o->_fft_in_jzz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jzz"); o->_fft_in_jxz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxz"); o->_Jxx = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); o->_Jzz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); o->_Jxz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE); o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE); o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE); } BLI_unlock_thread(LOCK_FFTW); BLI_rw_mutex_unlock(&o->oceanmutex); set_height_normalize_factor(o); BLI_rng_free(rng); }
/* already have tested for tface and ima and zspan */ static void shade_tface(BakeShade *bs) { VlakRen *vlr = bs->vlr; ObjectInstanceRen *obi = bs->obi; ObjectRen *obr = obi->obr; MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); Image *ima = tface->tpage; float vec[4][2]; int a, i1, i2, i3; /* check valid zspan */ if (ima != bs->ima) { BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); bs->ima = ima; bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA); /* note, these calls only free/fill contents of zspan struct, not zspan itself */ zbuf_free_span(bs->zspan); zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); } bs->rectx = bs->ibuf->x; bs->recty = bs->ibuf->y; bs->rect = bs->ibuf->rect; bs->rect_colorspace = bs->ibuf->rect_colorspace; bs->rect_float = bs->ibuf->rect_float; bs->vcol = NULL; bs->quad = 0; bs->rect_mask = NULL; bs->displacement_buffer = NULL; if (bs->use_mask || bs->use_displacement_buffer) { BakeImBufuserData *userdata = bs->ibuf->userdata; if (userdata == NULL) { BLI_lock_thread(LOCK_CUSTOM1); userdata = bs->ibuf->userdata; if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */ userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData"); if (bs->use_mask) { if (userdata->mask_buffer == NULL) { userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask"); } } if (bs->use_displacement_buffer) { if (userdata->displacement_buffer == NULL) { userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); } } bs->ibuf->userdata = userdata; BLI_unlock_thread(LOCK_CUSTOM1); } bs->rect_mask = userdata->mask_buffer; bs->displacement_buffer = userdata->displacement_buffer; } /* get pixel level vertex coordinates */ for (a = 0; a < 4; a++) { /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f); vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f); } /* UV indices have to be corrected for possible quad->tria splits */ i1 = 0; i2 = 1; i3 = 2; vlr_set_uv_indices(vlr, &i1, &i2, &i3); bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]); zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade); if (vlr->v4) { bs->quad = 1; bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]); zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade); } }
static int get_next_bake_face(BakeShade *bs) { ObjectRen *obr; VlakRen *vlr; MTFace *tface; static int v = 0, vdone = false; static ObjectInstanceRen *obi = NULL; if (bs == NULL) { vlr = NULL; v = vdone = false; obi = R.instancetable.first; return 0; } BLI_lock_thread(LOCK_CUSTOM1); for (; obi; obi = obi->next, v = 0) { obr = obi->obr; for (; v < obr->totvlak; v++) { vlr = RE_findOrAddVlak(obr, v); if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) { if (R.r.bake_flag & R_BAKE_VCOL) { /* Gather face data for vertex color bake */ Mesh *me; int *origindex, vcollayer; CustomDataLayer *cdl; if (obr->ob->type != OB_MESH) continue; me = obr->ob->data; origindex = RE_vlakren_get_origindex(obr, vlr, 0); if (origindex == NULL) continue; if (*origindex >= me->totpoly) { /* Small hack for Array modifier, which gives false * original indices - z0r */ continue; } #if 0 /* Only shade selected faces. */ if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0) continue; #endif vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL); if (vcollayer == -1) continue; cdl = &me->ldata.layers[vcollayer]; bs->mpoly = me->mpoly + *origindex; bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart; bs->mloop = me->mloop + bs->mpoly->loopstart; /* Tag mesh for reevaluation. */ me->id.flag |= LIB_DOIT; } else { Image *ima = NULL; ImBuf *ibuf = NULL; const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); if (!tface || !tface->tpage) continue; ima = tface->tpage; ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA); if (ibuf == NULL) continue; if (ibuf->rect == NULL && ibuf->rect_float == NULL) { BKE_image_release_ibuf(ima, ibuf, NULL); continue; } if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) { BKE_image_release_ibuf(ima, ibuf, NULL); continue; } if (ima->flag & IMA_USED_FOR_RENDER) { ima->id.flag &= ~LIB_DOIT; BKE_image_release_ibuf(ima, ibuf, NULL); continue; } /* find the image for the first time? */ if (ima->id.flag & LIB_DOIT) { ima->id.flag &= ~LIB_DOIT; /* we either fill in float or char, this ensures things go fine */ if (ibuf->rect_float) imb_freerectImBuf(ibuf); /* clear image */ if (R.r.bake_flag & R_BAKE_CLEAR) { if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); else IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); } /* might be read by UI to set active image for display */ R.bakebuf = ima; } /* Tag image for redraw. */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; BKE_image_release_ibuf(ima, ibuf, NULL); } bs->obi = obi; bs->vlr = vlr; bs->vdone++; /* only for error message if nothing was rendered */ v++; BLI_unlock_thread(LOCK_CUSTOM1); return 1; } } } BLI_unlock_thread(LOCK_CUSTOM1); return 0; }
void draw_image_main(const bContext *C, ARegion *ar) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); Image *ima; ImBuf *ibuf; float zoomx, zoomy; bool show_viewer, show_render, show_paint, show_stereo3d, show_multilayer; void *lock; /* XXX can we do this in refresh? */ #if 0 what_image(sima); if (sima->image) { ED_image_get_aspect(sima->image, &xuser_asp, &yuser_asp); /* UGLY hack? until now iusers worked fine... but for flipbook viewer we need this */ if (sima->image->type == IMA_TYPE_COMPOSITE) { ImageUser *iuser = ntree_get_active_iuser(scene->nodetree); if (iuser) { BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0); sima->iuser = *iuser; } } /* and we check for spare */ ibuf = ED_space_image_buffer(sima); } #endif /* retrieve the image and information about it */ ima = ED_space_image(sima); ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0; show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0; show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false)); show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO)); show_multilayer = ima && BKE_image_is_multilayer(ima); if (show_viewer) { /* use locked draw for drawing viewer image buffer since the compositor * is running in separated thread and compositor could free this buffers. * other images are not modifying in such a way so they does not require * lock (sergey) */ BLI_lock_thread(LOCK_DRAW_IMAGE); } if (show_stereo3d) { if (show_multilayer) /* update multiindex and pass for the current eye */ BKE_image_multilayer_index(ima->rr, &sima->iuser); else BKE_image_multiview_index(ima, &sima->iuser); } ibuf = ED_space_image_acquire_buffer(sima, &lock); /* draw the image or grid */ if (ibuf == NULL) ED_region_grid_draw(ar, zoomx, zoomy); else if (sima->flag & SI_DRAW_TILE) draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy); else if (ima && (ima->tpageflag & IMA_TILES)) draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy); else draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy); /* paint helpers */ if (show_paint) draw_image_paint_helpers(C, ar, scene, zoomx, zoomy); /* XXX integrate this code */ #if 0 if (ibuf) { float xoffs = 0.0f, yoffs = 0.0f; if (image_preview_active(sa, &xim, &yim)) { xoffs = scene->r.disprect.xmin; yoffs = scene->r.disprect.ymin; glColor3ub(0, 0, 0); calc_image_view(sima, 'f'); myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); glRectf(0.0f, 0.0f, 1.0f, 1.0f); glLoadIdentity(); } } #endif ED_space_image_release_buffer(sima, ibuf, lock); if (show_viewer) { BLI_unlock_thread(LOCK_DRAW_IMAGE); } /* render info */ if (ima && show_render) draw_render_info(C, sima->iuser.scene, ima, ar, zoomx, zoomy); }
void BKE_free_ocean_data(struct Ocean *oc) { if (!oc) return; BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE); BLI_lock_thread(LOCK_FFTW); if (oc->_do_disp_y) { fftw_destroy_plan(oc->_disp_y_plan); MEM_freeN(oc->_disp_y); } if (oc->_do_normals) { MEM_freeN(oc->_fft_in_nx); MEM_freeN(oc->_fft_in_nz); fftw_destroy_plan(oc->_N_x_plan); fftw_destroy_plan(oc->_N_z_plan); MEM_freeN(oc->_N_x); /*fftwf_free(oc->_N_y); (MEM01)*/ MEM_freeN(oc->_N_z); } if (oc->_do_chop) { MEM_freeN(oc->_fft_in_x); MEM_freeN(oc->_fft_in_z); fftw_destroy_plan(oc->_disp_x_plan); fftw_destroy_plan(oc->_disp_z_plan); MEM_freeN(oc->_disp_x); MEM_freeN(oc->_disp_z); } if (oc->_do_jacobian) { MEM_freeN(oc->_fft_in_jxx); MEM_freeN(oc->_fft_in_jzz); MEM_freeN(oc->_fft_in_jxz); fftw_destroy_plan(oc->_Jxx_plan); fftw_destroy_plan(oc->_Jzz_plan); fftw_destroy_plan(oc->_Jxz_plan); MEM_freeN(oc->_Jxx); MEM_freeN(oc->_Jzz); MEM_freeN(oc->_Jxz); } BLI_unlock_thread(LOCK_FFTW); if (oc->_fft_in) MEM_freeN(oc->_fft_in); /* check that ocean data has been initialized */ if (oc->_htilda) { MEM_freeN(oc->_htilda); MEM_freeN(oc->_k); MEM_freeN(oc->_h0); MEM_freeN(oc->_h0_minus); MEM_freeN(oc->_kx); MEM_freeN(oc->_kz); } BLI_rw_mutex_unlock(&oc->oceanmutex); }
static void screen_opengl_views_setup(OGLRender *oglrender) { RenderResult *rr; RenderView *rv; SceneRenderView *srv; bool is_multiview; View3D *v3d = oglrender->v3d; RenderData *rd = &oglrender->scene->r; rr = RE_AcquireResultWrite(oglrender->re); is_multiview = screen_opengl_is_multiview(oglrender); if (!is_multiview) { /* we only have one view when multiview is off */ rv = rr->views.first; if (rv == NULL) { rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); BLI_addtail(&rr->views, rv); } while (rv->next) { RenderView *rv_del = rv->next; BLI_remlink(&rr->views, rv_del); if (rv_del->rectf) MEM_freeN(rv_del->rectf); if (rv_del->rectz) MEM_freeN(rv_del->rectz); MEM_freeN(rv_del); } } else { if (!oglrender->is_sequencer) RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d)); /* remove all the views that are not needed */ rv = rr->views.last; while (rv) { srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)); if (BKE_scene_multiview_is_render_view_active(rd, srv)) { if (rv->rectf == NULL) rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect"); rv = rv->prev; } else { RenderView *rv_del = rv; rv = rv_del->prev; BLI_remlink(&rr->views, rv_del); if (rv_del->rectf) MEM_freeN(rv_del->rectf); if (rv_del->rectz) MEM_freeN(rv_del->rectz); MEM_freeN(rv_del); } } /* create all the views that are needed */ for (srv = rd->views.first; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) continue; rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)); if (rv == NULL) { rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); BLI_strncpy(rv->name, srv->name, sizeof(rv->name)); BLI_addtail(&rr->views, rv); } } } for (rv = rr->views.first; rv; rv = rv->next) { if (rv->rectf == NULL) { rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect"); } } BLI_lock_thread(LOCK_DRAW_IMAGE); if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) { oglrender->ima->flag |= IMA_IS_STEREO; } else { oglrender->ima->flag &= ~IMA_IS_STEREO; oglrender->iuser.flag &= ~IMA_SHOW_STEREO; } BLI_unlock_thread(LOCK_DRAW_IMAGE); RE_ReleaseResult(oglrender->re); }
static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth) { ListBase threads; OcclusionBuildThread othreads[BLENDER_MAX_THREADS]; OccNode *child, tmpnode; /* OccFace *face; */ int a, b, totthread = 0, offset[TOTCHILD], count[TOTCHILD]; /* add a new node */ node->occlusion = 1.0f; /* leaf node with only children */ if (end - begin <= TOTCHILD) { for (a = begin, b = 0; a < end; a++, b++) { /* face= &tree->face[a]; */ node->child[b].face = a; node->childflag |= (1 << b); } } else { /* order faces */ occ_build_8_split(tree, begin, end, offset, count); if (depth == 1 && tree->dothreadedbuild) BLI_init_threads(&threads, exec_occ_build, tree->totbuildthread); for (b = 0; b < TOTCHILD; b++) { if (count[b] == 0) { node->child[b].node = NULL; } else if (count[b] == 1) { /* face= &tree->face[offset[b]]; */ node->child[b].face = offset[b]; node->childflag |= (1 << b); } else { if (tree->dothreadedbuild) BLI_lock_thread(LOCK_CUSTOM1); child = BLI_memarena_alloc(tree->arena, sizeof(OccNode)); node->child[b].node = child; /* keep track of maximum depth for stack */ if (depth >= tree->maxdepth) tree->maxdepth = depth + 1; if (tree->dothreadedbuild) BLI_unlock_thread(LOCK_CUSTOM1); if (depth == 1 && tree->dothreadedbuild) { othreads[totthread].tree = tree; othreads[totthread].node = child; othreads[totthread].begin = offset[b]; othreads[totthread].end = offset[b] + count[b]; othreads[totthread].depth = depth + 1; BLI_insert_thread(&threads, &othreads[totthread]); totthread++; } else occ_build_recursive(tree, child, offset[b], offset[b] + count[b], depth + 1); } } if (depth == 1 && tree->dothreadedbuild) BLI_end_threads(&threads); } /* combine area, position and sh */ for (b = 0; b < TOTCHILD; b++) { if (node->childflag & (1 << b)) { child = &tmpnode; occ_node_from_face(tree->face + node->child[b].face, &tmpnode); } else { child = node->child[b].node; } if (child) { node->area += child->area; sh_add(node->sh, node->sh, child->sh); madd_v3_v3fl(node->co, child->co, child->area); } } if (node->area != 0.0f) mul_v3_fl(node->co, 1.0f / node->area); /* compute maximum distance from center */ node->dco = 0.0f; if (node->area > 0.0f) occ_build_dco(tree, node, node->co, &node->dco); }
static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, int clip_index, int frame, libmv_InputMode input_mode, int downscale, const libmv_Region *region, const libmv_FrameTransform *transform) { ImBuf *ibuf, *orig_ibuf, *final_ibuf; int64_t transform_key = 0; if (transform != NULL) { transform_key = libmv_frameAccessorgetTransformKey(transform); } /* First try to get fully processed image from the cache. */ ibuf = accesscache_get(accessor, clip_index, frame, input_mode, downscale, transform_key); if (ibuf != NULL) { return ibuf; } /* And now we do postprocessing of the original frame. */ orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame); if (orig_ibuf == NULL) { return NULL; } if (region != NULL) { int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1]; /* If the requested region goes outside of the actual frame we still * return the requested region size, but only fill it's partially with * the data we can. */ int clamped_origin_x = max_ii((int)region->min[0], 0), clamped_origin_y = max_ii((int)region->min[1], 0); int dst_offset_x = clamped_origin_x - (int)region->min[0], dst_offset_y = clamped_origin_y - (int)region->min[1]; int clamped_width = width - dst_offset_x, clamped_height = height - dst_offset_y; clamped_width = min_ii(clamped_width, orig_ibuf->x - clamped_origin_x); clamped_height = min_ii(clamped_height, orig_ibuf->y - clamped_origin_y); final_ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat); if (orig_ibuf->rect_float != NULL) { IMB_rectcpy(final_ibuf, orig_ibuf, dst_offset_x, dst_offset_y, clamped_origin_x, clamped_origin_y, clamped_width, clamped_height); } else { int y; /* TODO(sergey): We don't do any color space or alpha conversion * here. Probably Libmv is better to work in the linear space, * but keep sRGB space here for compatibility for now. */ for (y = 0; y < clamped_height; ++y) { int x; for (x = 0; x < clamped_width; ++x) { int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y; int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y; int dst_index = (dst_y * width + dst_x) * 4, src_index = (src_y * orig_ibuf->x + src_x) * 4; rgba_uchar_to_float(final_ibuf->rect_float + dst_index, (unsigned char *)orig_ibuf->rect + src_index); } } } } else { /* Libmv only works with float images, * * This would likely make it so loads of float buffers are being stored * in the cache which is nice on the one hand (faster re-use of the * frames) but on the other hand it bumps the memory usage up. */ BLI_lock_thread(LOCK_MOVIECLIP); IMB_float_from_rect(orig_ibuf); BLI_unlock_thread(LOCK_MOVIECLIP); final_ibuf = orig_ibuf; } if (downscale > 0) { if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); } IMB_scaleImBuf(final_ibuf, ibuf->x / (1 << downscale), ibuf->y / (1 << downscale)); } if (transform != NULL) { libmv_FloatImage input_image, output_image; ibuf_to_float_image(final_ibuf, &input_image); libmv_frameAccessorgetTransformRun(transform, &input_image, &output_image); if (final_ibuf != orig_ibuf) { IMB_freeImBuf(final_ibuf); } final_ibuf = float_image_to_ibuf(&output_image); libmv_floatImageDestroy(&output_image); } if (input_mode == LIBMV_IMAGE_MODE_RGBA) { BLI_assert(ibuf->channels == 3 || ibuf->channels == 4); /* pass */ } else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ { if (final_ibuf->channels != 1) { ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf); if (final_ibuf != orig_ibuf) { /* We dereference original frame later. */ IMB_freeImBuf(final_ibuf); } final_ibuf = grayscale_ibuf; } } /* it's possible processing still didn't happen at this point, * but we really need a copy of the buffer to be transformed * and to be put to the cache. */ if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); } IMB_freeImBuf(orig_ibuf); /* We put postprocessed frame to the cache always for now, * not the smartest thing in the world, but who cares at this point. */ /* TODO(sergey): Disable cache for now, because we don't store region * in the cache key and can't check whether cached version is usable for * us or not. * * Need to think better about what to cache and when. */ if (false) { accesscache_put(accessor, clip_index, frame, input_mode, downscale, transform_key, final_ibuf); } return final_ibuf; }