void WorkScheduler::start(CompositorContext &context) { #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE unsigned int index; g_cpuqueue = BLI_thread_queue_init(); BLI_init_threads(&g_cputhreads, thread_execute_cpu, g_cpudevices.size()); for (index = 0; index < g_cpudevices.size(); index++) { Device *device = g_cpudevices[index]; BLI_insert_thread(&g_cputhreads, device); } #ifdef COM_OPENCL_ENABLED if (context.getHasActiveOpenCLDevices()) { g_gpuqueue = BLI_thread_queue_init(); BLI_init_threads(&g_gputhreads, thread_execute_gpu, g_gpudevices.size()); for (index = 0; index < g_gpudevices.size(); index++) { Device *device = g_gpudevices[index]; BLI_insert_thread(&g_gputhreads, device); } g_openclActive = true; } else { g_openclActive = false; } #endif #endif }
void BLI_insert_work(ThreadedWorker *worker, void *param) { WorkParam *p = MEM_callocN(sizeof(WorkParam), "workparam"); int index; if (BLI_available_threads(&worker->threadbase) == 0) { index = worker->total; while(index == worker->total) { PIL_sleep_ms(worker->sleep_time); for (index = 0; index < worker->total; index++) { if (worker->busy[index] == 0) { BLI_remove_thread_index(&worker->threadbase, index); break; } } } } else { index = BLI_available_thread_index(&worker->threadbase); } worker->busy[index] = 1; p->param = param; p->index = index; p->worker = worker; BLI_insert_thread(&worker->threadbase, p); }
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame, short render_size, short render_flag, short *stop, short *do_update, float *progress) { ListBase threads; PrefetchQueue queue; PrefetchThread *handles; int tot_thread = BLI_system_thread_count(); int i; /* reserve one thread for the interface */ if (tot_thread > 1) tot_thread--; /* initialize queue */ BLI_spin_init(&queue.spin); queue.current_frame = current_frame; queue.initial_frame = current_frame; queue.start_frame = start_frame; queue.end_frame = end_frame; queue.render_size = render_size; queue.render_flag = render_flag; queue.direction = 1; queue.stop = stop; queue.do_update = do_update; queue.progress = progress; /* fill in thread handles */ handles = MEM_callocN(sizeof(PrefetchThread) * tot_thread, "prefetch threaded handles"); if (tot_thread > 1) BLI_init_threads(&threads, do_prefetch_thread, tot_thread); for (i = 0; i < tot_thread; i++) { PrefetchThread *handle = &handles[i]; handle->clip = clip; handle->queue = &queue; if (tot_thread > 1) BLI_insert_thread(&threads, handle); } /* run the threads */ if (tot_thread > 1) BLI_end_threads(&threads); else do_prefetch_thread(handles); MEM_freeN(handles); }
/* if different owner starts existing startjob, it suspends itself */ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) { if (wm_job->running) { /* signal job to end and restart */ wm_job->stop = TRUE; // printf("job started a running job, ending... %s\n", wm_job->name); } else { if (wm_job->customdata && wm_job->startjob) { wm_jobs_test_suspend_stop(wm, wm_job); if (wm_job->suspended == FALSE) { /* copy to ensure proper free in end */ wm_job->run_customdata = wm_job->customdata; wm_job->run_free = wm_job->free; wm_job->free = NULL; wm_job->customdata = NULL; wm_job->running = TRUE; if (wm_job->initjob) wm_job->initjob(wm_job->run_customdata); wm_job->stop = FALSE; wm_job->ready = FALSE; wm_job->progress = 0.0; // printf("job started: %s\n", wm_job->name); BLI_init_threads(&wm_job->threads, do_job_thread, 1); BLI_insert_thread(&wm_job->threads, wm_job); } /* restarted job has timer already */ if (wm_job->wt == NULL) wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, wm_job->timestep); if (G.debug & G_DEBUG_JOBS) wm_job->start_time = PIL_check_seconds_timer(); } else { printf("job fails, not initialized\n"); } } }
/* if different owner starts existing startjob, it suspends itself */ void WM_jobs_start(wmWindowManager *wm, wmJob *steve) { if(steve->running) { /* signal job to end and restart */ steve->stop= 1; // printf("job started a running job, ending... %s\n", steve->name); } else { if(steve->customdata && steve->startjob) { wm_jobs_test_suspend_stop(wm, steve); if(steve->suspended==0) { /* copy to ensure proper free in end */ steve->run_customdata= steve->customdata; steve->run_free= steve->free; steve->free= NULL; steve->customdata= NULL; steve->running= 1; if(steve->initjob) steve->initjob(steve->run_customdata); steve->stop= 0; steve->ready= 0; steve->progress= 0.0; // printf("job started: %s\n", steve->name); BLI_init_threads(&steve->threads, do_job_thread, 1); BLI_insert_thread(&steve->threads, steve); } /* restarted job has timer already */ if(steve->wt==NULL) steve->wt= WM_event_add_timer(wm, steve->win, TIMERJOBS, steve->timestep); } else printf("job fails, not initialized\n"); } }
// start thread to cache video frame from file/capture/stream // this function should be called only when the position in the stream is set for the // first frame to cache bool VideoFFmpeg::startCache() { if (!m_cacheStarted && m_isThreaded) { m_stopThread = false; for (int i=0; i<CACHE_FRAME_SIZE; i++) { CacheFrame *frame = new CacheFrame(); frame->frame = allocFrameRGB(); BLI_addtail(&m_frameCacheFree, frame); } for (int i=0; i<CACHE_PACKET_SIZE; i++) { CachePacket *packet = new CachePacket(); BLI_addtail(&m_packetCacheFree, packet); } BLI_init_threads(&m_thread, cacheThread, 1); BLI_insert_thread(&m_thread, this); m_cacheStarted = true; } return m_cacheStarted; }
/* optimized tree execute test for compositing */ static void ntreeCompositExecTreeOld(bNodeTree *ntree, RenderData *rd, int do_preview) { bNodeExec *nodeexec; bNode *node; ListBase threads; ThreadData thdata; int totnode, curnode, rendering = TRUE, n; bNodeTreeExec *exec = ntree->execdata; if (do_preview) ntreeInitPreview(ntree, 0, 0); if (!ntree->execdata) { /* XXX this is the top-level tree, so we use the ntree->execdata pointer. */ exec = ntreeCompositBeginExecTree(ntree, 1); } ntree_composite_texnode(ntree, 1); /* prevent unlucky accidents */ if (G.background) rd->scemode &= ~R_COMP_CROP; /* setup callerdata for thread callback */ thdata.rd= rd; thdata.stack= exec->stack; /* fixed seed, for example noise texture */ BLI_srandom(rd->cfra); /* sets need_exec tags in nodes */ curnode = totnode= setExecutableNodes(exec, &thdata); BLI_init_threads(&threads, exec_composite_node, rd->threads); while (rendering) { if (BLI_available_threads(&threads)) { nodeexec= getExecutableNode(exec); if (nodeexec) { node = nodeexec->node; if (ntree->progress && totnode) ntree->progress(ntree->prh, (1.0f - curnode/(float)totnode)); if (ntree->stats_draw) { char str[128]; BLI_snprintf(str, sizeof(str), "Compositing %d %s", curnode, node->name); ntree->stats_draw(ntree->sdh, str); } curnode--; node->threaddata = &thdata; node->exec= NODE_PROCESSING; BLI_insert_thread(&threads, nodeexec); } else PIL_sleep_ms(50); } else PIL_sleep_ms(50); rendering= 0; /* test for ESC */ if (ntree->test_break && ntree->test_break(ntree->tbh)) { for (node= ntree->nodes.first; node; node= node->next) node->exec |= NODE_READY; } /* check for ready ones, and if we need to continue */ for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) { node = nodeexec->node; if (node->exec & NODE_READY) { if ((node->exec & NODE_FINISHED)==0) { BLI_remove_thread(&threads, nodeexec); /* this waits for running thread to finish btw */ node->exec |= NODE_FINISHED; /* freeing unused buffers */ if (rd->scemode & R_COMP_FREE) freeExecutableNode(exec); } } else rendering= 1; } } BLI_end_threads(&threads); /* XXX top-level tree uses the ntree->execdata pointer */ ntreeCompositEndExecTree(exec, 1); }
static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_tangent, MPassKnownData passKnownData, MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData) { DerivedMesh *dm = bkr->lores_dm; const int lvl = bkr->lvl; const int tot_face = dm->getNumTessFaces(dm); if (tot_face > 0) { MultiresBakeThread *handles; MultiresBakeQueue queue; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); MVert *mvert = dm->getVertArray(dm); MFace *mface = dm->getTessFaceArray(dm); MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); float *precomputed_normals = dm->getTessFaceDataArray(dm, CD_NORMAL); float *pvtangent = NULL; ListBase threads; int i, tot_thread = bkr->threads > 0 ? bkr->threads : BLI_system_thread_count(); void *bake_data = NULL; if (require_tangent) { if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) DM_add_tangent_layer(dm); pvtangent = DM_get_tessface_data_layer(dm, CD_TANGENT); } /* all threads shares the same custom bake data */ if (initBakeData) bake_data = initBakeData(bkr, ima); if (tot_thread > 1) BLI_init_threads(&threads, do_multires_bake_thread, tot_thread); handles = MEM_callocN(tot_thread * sizeof(MultiresBakeThread), "do_multires_bake handles"); /* faces queue */ queue.cur_face = 0; queue.tot_face = tot_face; BLI_spin_init(&queue.spin); /* fill in threads handles */ for (i = 0; i < tot_thread; i++) { MultiresBakeThread *handle = &handles[i]; handle->bkr = bkr; handle->image = ima; handle->queue = &queue; handle->data.mface = mface; handle->data.mvert = mvert; handle->data.mtface = mtface; handle->data.pvtangent = pvtangent; handle->data.precomputed_normals = precomputed_normals; /* don't strictly need this */ handle->data.w = ibuf->x; handle->data.h = ibuf->y; handle->data.lores_dm = dm; handle->data.hires_dm = bkr->hires_dm; handle->data.lvl = lvl; handle->data.pass_data = passKnownData; handle->data.bake_data = bake_data; handle->data.ibuf = ibuf; init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel); if (tot_thread > 1) BLI_insert_thread(&threads, handle); } /* run threads */ if (tot_thread > 1) BLI_end_threads(&threads); else do_multires_bake_thread(&handles[0]); BLI_spin_end(&queue.spin); /* finalize baking */ if (applyBakeData) applyBakeData(bake_data); if (freeBakeData) freeBakeData(bake_data); BKE_image_release_ibuf(ima, ibuf, NULL); } }
/* Precache a volume into a 3D voxel grid. * The voxel grid is stored in the ObjectInstanceRen, * in camera space, aligned with the ObjectRen's bounding box. * Resolution is defined by the user. */ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma) { VolumePrecache *vp; VolPrecachePart *nextpa, *pa; RayObject *tree; ShadeInput shi; ListBase threads; float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1]; int parts[3] = {1, 1, 1}, totparts; int caching=1, counter=0; int totthread = re->r.threads; double time, lasttime= PIL_check_seconds_timer(); R = *re; /* create a raytree with just the faces of the instanced ObjectRen, * used for checking if the cached point is inside or outside. */ //tree = create_raytree_obi(obi, bbmin, bbmax); tree = makeraytree_object(&R, obi); if (!tree) return; INIT_MINMAX(bbmin, bbmax); RE_rayobject_merge_bb( tree, bbmin, bbmax); vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache"); if (!precache_resolution(vp, bbmin, bbmax, ma->vol.precache_resolution)) { MEM_freeN(vp); vp = NULL; return; } vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel"); vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel"); vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel"); obi->volume_precache = vp; /* Need a shadeinput to calculate scattering */ precache_setup_shadeinput(re, obi, ma, &shi); precache_init_parts(re, tree, &shi, obi, totthread, parts); totparts = parts[0] * parts[1] * parts[2]; BLI_init_threads(&threads, vol_precache_part, totthread); while(caching) { if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) { nextpa = precache_get_new_part(re); if (nextpa) { nextpa->working = 1; BLI_insert_thread(&threads, nextpa); } } else PIL_sleep_ms(50); caching=0; counter=0; for(pa= re->volume_precache_parts.first; pa; pa= pa->next) { if(pa->done) { counter++; BLI_remove_thread(&threads, pa); } else caching = 1; } if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread) caching=0; time= PIL_check_seconds_timer(); if(time-lasttime>1.0f) { char str[64]; sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts))); re->i.infostr= str; re->stats_draw(re->sdh, &re->i); re->i.infostr= NULL; lasttime= time; } } BLI_end_threads(&threads); BLI_freelistN(&re->volume_precache_parts); if(tree) { //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it //RE_rayobject_free(tree); //tree= NULL; } lightcache_filter(obi->volume_precache); if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { multiple_scattering_diffusion(re, vp, ma); } }
/* returns 0 if nothing was handled */ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress) { BakeShade *handles; ListBase threads; Image *ima; int a, vdone = false, result = BAKE_RESULT_OK; bool use_mask = false; bool use_displacement_buffer = false; re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene); /* initialize render global */ R = *re; R.bakebuf = NULL; /* initialize static vars */ get_next_bake_face(NULL); /* do we need a mask? */ if (re->r.bake_filter) use_mask = true; /* do we need buffer to store displacements */ if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) || (type == RE_BAKE_DERIVATIVE)) { use_displacement_buffer = true; use_mask = true; } } /* baker uses this flag to detect if image was initialized */ if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { for (ima = G.main->image.first; ima; ima = ima->id.next) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA); ima->id.flag |= LIB_DOIT; ima->flag &= ~IMA_USED_FOR_RENDER; if (ibuf) { ibuf->userdata = NULL; /* use for masking if needed */ } BKE_image_release_ibuf(ima, ibuf, NULL); } } if (R.r.bake_flag & R_BAKE_VCOL) { /* untag all meshes */ tag_main_lb(&G.main->mesh, false); } BLI_init_threads(&threads, do_bake_thread, re->r.threads); handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade"); /* get the threads running */ for (a = 0; a < re->r.threads; a++) { /* set defaults in handles */ handles[a].ssamp.shi[0].lay = re->lay; if (type == RE_BAKE_SHADOW) { handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW; } else { handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED; } handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC); handles[a].ssamp.shi[0].thread = a; handles[a].ssamp.tot = 1; handles[a].type = type; handles[a].actob = actob; if (R.r.bake_flag & R_BAKE_VCOL) handles[a].zspan = NULL; else handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake"); handles[a].use_mask = use_mask; handles[a].use_displacement_buffer = use_displacement_buffer; handles[a].do_update = do_update; /* use to tell the view to update */ handles[a].displacement_min = FLT_MAX; handles[a].displacement_max = -FLT_MAX; BLI_insert_thread(&threads, &handles[a]); } /* wait for everything to be done */ a = 0; while (a != re->r.threads) { PIL_sleep_ms(50); /* calculate progress */ for (vdone = false, a = 0; a < re->r.threads; a++) vdone += handles[a].vdone; if (progress) *progress = (float)(vdone / (float)re->totvlak); for (a = 0; a < re->r.threads; a++) { if (handles[a].ready == false) { break; } } } /* filter and refresh images */ if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { float displacement_min = FLT_MAX, displacement_max = -FLT_MAX; if (use_displacement_buffer) { for (a = 0; a < re->r.threads; a++) { displacement_min = min_ff(displacement_min, handles[a].displacement_min); displacement_max = max_ff(displacement_max, handles[a].displacement_max); } } for (ima = G.main->image.first; ima; ima = ima->id.next) { if ((ima->id.flag & LIB_DOIT) == 0) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA); BakeImBufuserData *userdata; if (ima->flag & IMA_USED_FOR_RENDER) result = BAKE_RESULT_FEEDBACK_LOOP; if (!ibuf) continue; userdata = (BakeImBufuserData *)ibuf->userdata; if (userdata) { if (use_displacement_buffer) { if (type == RE_BAKE_DERIVATIVE) { float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f; RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer, displacement_min, displacement_max, user_scale); } else { RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, displacement_min, displacement_max); } } RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); } ibuf->userflags |= IB_BITMAPDIRTY; BKE_image_release_ibuf(ima, ibuf, NULL); } } /* calculate return value */ for (a = 0; a < re->r.threads; a++) { zbuf_free_span(handles[a].zspan); MEM_freeN(handles[a].zspan); } } MEM_freeN(handles); BLI_end_threads(&threads); if (vdone == 0) { result = BAKE_RESULT_NO_OBJECTS; } return result; }
static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count, int *build_undistort_sizes, int build_undistort_count, short *stop, short *do_update, float *progress) { ProxyJob *pj = pjv; MovieClip *clip = pj->clip; Scene *scene = pj->scene; int sfra = SFRA, efra = EFRA; ProxyThread *handles; ListBase threads; int i, tot_thread = BLI_system_thread_count(); ProxyQueue queue; BLI_spin_init(&queue.spin); queue.cfra = sfra; queue.sfra = sfra; queue.efra = efra; queue.stop = stop; queue.do_update = do_update; queue.progress = progress; handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles"); if (tot_thread > 1) BLI_init_threads(&threads, do_proxy_thread, tot_thread); for (i = 0; i < tot_thread; i++) { ProxyThread *handle = &handles[i]; handle->clip = clip; handle->queue = &queue; handle->build_count = build_count; handle->build_sizes = build_sizes; handle->build_undistort_count = build_undistort_count; handle->build_undistort_sizes = build_undistort_sizes; if (build_undistort_count) handle->distortion = BKE_tracking_distortion_new(); if (tot_thread > 1) BLI_insert_thread(&threads, handle); } if (tot_thread > 1) BLI_end_threads(&threads); else do_proxy_thread(handles); MEM_freeN(handles); if (build_undistort_count) { for (i = 0; i < tot_thread; i++) { ProxyThread *handle = &handles[i]; BKE_tracking_distortion_free(handle->distortion); } } }
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); }
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; }