void OutputOpenExrMultiLayerOperation::deinitExecution() { unsigned int width = this->getWidth(); unsigned int height = this->getHeight(); if (width != 0 && height != 0) { Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; void *exrhandle = IMB_exr_get_handle(); BKE_makepicstring_from_type(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, (this->m_rd->scemode & R_EXTENSION), true); BLI_make_existing_file(filename); for (unsigned int i = 0; i < this->m_layers.size(); ++i) { OutputOpenExrLayer &layer = this->m_layers[i]; if (!layer.imageInput) continue; /* skip unconnected sockets */ char channelname[EXR_TOT_MAXNAME]; BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2); char *channelname_ext = channelname + strlen(channelname); float *buf = this->m_layers[i].outputBuffer; /* create channels */ switch (this->m_layers[i].datatype) { case COM_DT_VALUE: strcpy(channelname_ext, ".V"); IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf); break; case COM_DT_VECTOR: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1); strcpy(channelname_ext, ".Z"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2); break; case COM_DT_COLOR: strcpy(channelname_ext, ".R"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf); strcpy(channelname_ext, ".G"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1); strcpy(channelname_ext, ".B"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2); strcpy(channelname_ext, ".A"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3); break; default: break; } } /* when the filename has no permissions, this can fail */ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec)) { IMB_exr_write_channels(exrhandle); } else { /* TODO, get the error from openexr's exception */ /* XXX nice way to do report? */ printf("Error Writing Render Result, see console\n"); } IMB_exr_close(exrhandle); for (unsigned int i = 0; i < this->m_layers.size(); ++i) { if (this->m_layers[i].outputBuffer) { MEM_freeN(this->m_layers[i].outputBuffer); this->m_layers[i].outputBuffer = NULL; } this->m_layers[i].imageInput = NULL; } } }
/* function used for WM_OT_save_mainfile too */ static int wm_collada_export_exec(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; int apply_modifiers; int export_mesh_type; int selected; int include_children; int include_armatures; int include_shapekeys; int deform_bones_only; int include_uv_textures; int include_material_textures; int use_texture_copies; int active_uv_only; int triangulate; int use_object_instantiation; int sort_by_name; int export_transformation_type; int open_sim; int export_count; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); return OPERATOR_CANCELLED; } RNA_string_get(op->ptr, "filepath", filepath); BLI_ensure_extension(filepath, sizeof(filepath), ".dae"); /* Avoid File write exceptions in Collada */ if (!BLI_exists(filepath)) { BLI_make_existing_file(filepath); if (!BLI_file_touch(filepath)) { BKE_report(op->reports, RPT_ERROR, "Can't create export file"); fprintf(stdout, "Collada export: Can not create: %s\n", filepath); return OPERATOR_CANCELLED; } } else if (!BLI_file_is_writable(filepath)) { BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file"); fprintf(stdout, "Collada export: Can not modify: %s\n", filepath); return OPERATOR_CANCELLED; } /* Now the exporter can create and write the export file */ /* Options panel */ apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); export_mesh_type = RNA_enum_get(op->ptr, "export_mesh_type_selection"); selected = RNA_boolean_get(op->ptr, "selected"); include_children = RNA_boolean_get(op->ptr, "include_children"); include_armatures = RNA_boolean_get(op->ptr, "include_armatures"); include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys"); deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only"); include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures"); include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures"); use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies"); active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only"); triangulate = RNA_boolean_get(op->ptr, "triangulate"); use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name"); export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection"); open_sim = RNA_boolean_get(op->ptr, "open_sim"); /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); export_count = collada_export(CTX_data_scene(C), filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, use_texture_copies, triangulate, use_object_instantiation, sort_by_name, export_transformation_type, open_sim); if (export_count == 0) { BKE_report(op->reports, RPT_WARNING, "Export file is empty"); return OPERATOR_CANCELLED; } else { char buff[100]; sprintf(buff, "Exported %d Objects", export_count); BKE_report(op->reports, RPT_INFO, buff); return OPERATOR_FINISHED; } }
static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( struct anim *anim, AVStream *st, int proxy_size, int width, int height, int quality) { struct proxy_output_ctx *rv = MEM_callocN( sizeof(struct proxy_output_ctx), "alloc_proxy_output"); char fname[FILE_MAX]; int ffmpeg_quality; /* JPEG requires this */ width = round_up(width, 8); height = round_up(height, 8); rv->proxy_size = proxy_size; rv->anim = anim; get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE); BLI_make_existing_file(fname); rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); BLI_strncpy(rv->of->filename, fname, sizeof(rv->of->filename)); fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename); rv->st = avformat_new_stream(rv->of, NULL); rv->st->id = 0; rv->c = rv->st->codec; rv->c->codec_type = AVMEDIA_TYPE_VIDEO; rv->c->codec_id = AV_CODEC_ID_MJPEG; rv->c->width = width; rv->c->height = height; rv->of->oformat->video_codec = rv->c->codec_id; rv->codec = avcodec_find_encoder(rv->c->codec_id); if (!rv->codec) { fprintf(stderr, "No ffmpeg MJPEG encoder available? " "Proxy not built!\n"); av_free(rv->of); return NULL; } if (rv->codec->pix_fmts) { rv->c->pix_fmt = rv->codec->pix_fmts[0]; } else { rv->c->pix_fmt = PIX_FMT_YUVJ420P; } rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->codec->sample_aspect_ratio; rv->c->time_base.den = 25; rv->c->time_base.num = 1; rv->st->time_base = rv->c->time_base; /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence, * but this seems to be giving expected quality result */ ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f); av_opt_set_int(rv->c, "qmin", ffmpeg_quality, 0); av_opt_set_int(rv->c, "qmax", ffmpeg_quality, 0); if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Couldn't open outputfile! " "Proxy not built!\n"); av_free(rv->of); return 0; } avcodec_open2(rv->c, rv->codec, NULL); rv->orig_height = av_get_cropped_height_from_codec(st->codec); if (st->codec->width != width || st->codec->height != height || st->codec->pix_fmt != rv->c->pix_fmt) { rv->frame = avcodec_alloc_frame(); avpicture_fill((AVPicture *) rv->frame, MEM_mallocN(avpicture_get_size( rv->c->pix_fmt, round_up(width, 16), height), "alloc proxy output frame"), rv->c->pix_fmt, round_up(width, 16), height); rv->sws_ctx = sws_getContext( st->codec->width, rv->orig_height, st->codec->pix_fmt, width, height, rv->c->pix_fmt, SWS_FAST_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); } if (avformat_write_header(rv->of, NULL) < 0) { fprintf(stderr, "Couldn't set output parameters? " "Proxy not built!\n"); av_free(rv->of); return 0; } return rv; }
static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer) { FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); FluidsimSettings *domainSettings= fluidmd->fss; FILE *fileCfg; int dirExist = 0; char newSurfdataPath[FILE_MAX]; /* modified output settings */ const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; int outStringsChanged = 0; /* prepare names... */ const char *relbase= modifier_path_relbase(fsDomain); BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */ BLI_path_abs(targetDir, relbase); /* fixed #frame-no */ /* .tmp: don't overwrite/delete original file */ BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); // 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 = BLI_fopen(targetFile, "w"); if (fileCfg) { dirExist = 1; fclose(fileCfg); // remove cfg dummy from directory test BLI_delete(targetFile, false, false); } if (targetDir[0] == '\0' || (!dirExist)) { char blendFile[FILE_MAX]; // invalid dir, reset to current/previous BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile)); BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */ BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); BLI_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 0 if (outStringsChanged) { char dispmsg[FILE_MAX+256]; int selection=0; BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg)); 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 */ BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir)); strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */ } #endif return outStringsChanged; }
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *relbase= modifier_path_relbase(fsDomain); const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; const char *suffixSurface = FLUID_SUFFIX_SURFACE; char targetDir[FILE_MAX]; // store & modify output settings char targetFile[FILE_MAX]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); if (getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName); 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)"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldn't be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* delete old baked files */ fluidsim_delete_until_lastframe(domainSettings, relbase); /* rough check of settings... */ if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "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; } BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels); elbeemDebugOut(debugStrBuffer); /* ******** prepare output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; /* ******** initialize and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, 1); /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if (!invert_m4_m4(invDomMat, domainMat)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, don't overwrite/delete original file BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); // make sure these directories exist as well if (outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, 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; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; 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; /* use domainobsType also for surface generation flag (bit: >=64) */ if (domainSettings->typeFlags & OB_FSSG_NOOBS) fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; else fsset->mFsSurfGenSetting = 0; // "normal" mode fsset->generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender domain transform matrix { int j; for (i=0; i<4; i++) { for (j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; if (do_job) { wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID); /* setup job */ WM_jobs_customdata_set(wm_job, fb, fluidbake_free); WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } else { short dummy_stop = 0, dummy_do_update = 0; float dummy_progress = 0.0f; /* blocking, use with exec() */ fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); fluidbake_endjob((void *)fb); fluidbake_free((void *)fb); } /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }
/* write input data into layers */ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack **in) { Main *bmain= G.main; /* TODO, have this passed along */ NodeImageMultiFile *nimf= node->storage; void *exrhandle= IMB_exr_get_handle(); char filename[FILE_MAX]; bNodeSocket *sock; int i; /* Must have consistent pixel size for exr file, simply take the first valid input size. */ int rectx = -1; int recty = -1; int has_preview = 0; BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE); BLI_make_existing_file(filename); for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) { if (in[i]->data) { NodeImageMultiFileSocket *sockdata = sock->storage; CompBuf *cbuf = in[i]->data; char channelname[EXR_TOT_MAXNAME]; /* '.' and single character channel name is appended */ char *channelname_ext; if (cbuf->rect_procedural) { printf("Error writing multilayer EXR: Procedural buffer not supported\n"); continue; } if (rectx < 0) { rectx = cbuf->x; recty = cbuf->y; } else if (cbuf->x != rectx || cbuf->y != recty) { printf("Error: Multilayer EXR output node %s expects same resolution for all input buffers. Layer %s skipped.\n", node->name, sock->name); continue; } BLI_strncpy(channelname, sockdata->layer, sizeof(channelname)-2); channelname_ext = channelname + strlen(channelname); /* create channels */ switch (cbuf->type) { case CB_VAL: strcpy(channelname_ext, ".V"); IMB_exr_add_channel(exrhandle, NULL, channelname, 1, rectx, cbuf->rect); break; case CB_VEC2: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, NULL, channelname, 2, 2*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, NULL, channelname, 2, 2*rectx, cbuf->rect+1); break; case CB_VEC3: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect+1); strcpy(channelname_ext, ".Z"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect+2); break; case CB_RGBA: strcpy(channelname_ext, ".R"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect); strcpy(channelname_ext, ".G"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+1); strcpy(channelname_ext, ".B"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+2); strcpy(channelname_ext, ".A"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+3); break; } /* simply pick the first valid input for preview */ if (!has_preview) { generate_preview(rd, node, cbuf); has_preview = 1; } } } /* when the filename has no permissions, this can fail */ if (IMB_exr_begin_write(exrhandle, filename, rectx, recty, nimf->format.exr_codec)) { IMB_exr_write_channels(exrhandle); } else { /* TODO, get the error from openexr's exception */ /* XXX nice way to do report? */ printf("Error Writing Render Result, see console\n"); } IMB_exr_close(exrhandle); }
/* called from within UI and render pipeline, saves both rendered result as a file-read result * if multiview is true saves all views in a multiview exr * else if view is not NULL saves single view * else saves stereo3d */ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view) { RenderLayer *rl; RenderPass *rpass; RenderView *rview; void *exrhandle = IMB_exr_get_handle(); bool success; int a, nr; const char *chan_view = NULL; int compress = (imf ? imf->exr_codec : 0); size_t width, height; const bool is_mono = view && !multiview; const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false; width = rr->rectx; height = rr->recty; if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) { /* single layer OpenEXR */ const char *RGBAZ[] = {"R", "G", "B", "A", "Z"}; for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { IMB_exr_add_view(exrhandle, rview->name); if (rview->rectf) { for (a = 0; a < 4; a++) { IMB_exr_add_channel(exrhandle, "", RGBAZ[a], rview->name, 4, 4 * width, rview->rectf + a, use_half_float); } if (rview->rectz) { /* Z pass is always stored as float. */ IMB_exr_add_channel(exrhandle, "", RGBAZ[4], rview->name, 1, width, rview->rectz, false); } } } } else { for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { if (is_mono) { if (!STREQ(view, rview->name)) { continue; } chan_view = ""; } else { /* if rendered only one view, we treat as a a non-view render */ chan_view = rview->name; } IMB_exr_add_view(exrhandle, rview->name); if (rview->rectf) { for (a = 0; a < 4; a++) { IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a), chan_view, 4, 4 * width, rview->rectf + a, use_half_float); } } } /* add layers/passes and assign channels */ for (rl = rr->layers.first; rl; rl = rl->next) { /* passes are allocated in sync */ for (rpass = rl->passes.first; rpass; rpass = rpass->next) { const int xstride = rpass->channels; if (is_mono) { if (!STREQ(view, rpass->view)) { continue; } chan_view = ""; } else { /* if rendered only one view, we treat as a a non-view render */ chan_view = (nr > 1 ? rpass->view :""); } for (a = 0; a < xstride; a++) { if (rpass->passtype) { IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view, xstride, xstride * width, rpass->rect + a, rpass->passtype == SCE_PASS_Z ? false : use_half_float); } else { IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view, xstride, xstride * width, rpass->rect + a, use_half_float); } } } } } BLI_make_existing_file(filename); if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) { IMB_exr_write_channels(exrhandle); success = true; } else { /* TODO, get the error from openexr's exception */ BKE_report(reports, RPT_ERROR, "Error writing render result (see console)"); success = false; } IMB_exr_close(exrhandle); return success; }
/* Get the output filename-- similar to the other output formats */ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix) { char autosplit[20]; const char **exts = get_file_extensions(rd->ffcodecdata.type); const char **fe = exts; int sfra, efra; if (!string || !exts) return; if (preview) { sfra = rd->psfra; efra = rd->pefra; } else { sfra = rd->sfra; efra = rd->efra; } strcpy(string, rd->pic); BLI_path_abs(string, G.main->name); BLI_make_existing_file(string); autosplit[0] = 0; if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { if (context) { sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count); } } if (rd->scemode & R_EXTENSION) { while (*fe) { if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), *fe) == 0) { break; } fe++; } if (*fe == NULL) { strcat(string, autosplit); BLI_path_frame_range(string, sfra, efra, 4); strcat(string, *exts); } else { *(string + strlen(string) - strlen(*fe)) = 0; strcat(string, autosplit); strcat(string, *fe); } } else { if (BLI_path_frame_check_chars(string)) { BLI_path_frame_range(string, sfra, efra, 4); } strcat(string, autosplit); } BLI_path_suffix(string, FILE_MAX, suffix, ""); }
int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, int guimode) { int file, number; int ret_value = RET_OK; bool remove_tmp = false; char name[FILE_MAX]; char tempname[FILE_MAX]; /* void *data; */ if (guimode) {} //XXX waitcursor(1); BLI_strncpy(name, filename, sizeof(name)); BLI_path_abs(name, G.main->name); if (BLI_exists(name)) { for (number = 1; number <= 999; number++) { BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number); if (!BLI_exists(tempname)) { if (BLI_copy(name, tempname) == RET_OK) { remove_tmp = true; } break; } } } /* make sure the path to the file exists... */ BLI_make_existing_file(name); file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); if (file == -1) { BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name); ret_value = RET_ERROR; } else { if (write(file, pf->data, pf->size) != pf->size) { BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name); ret_value = RET_ERROR; } else { BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name); } close(file); } if (remove_tmp) { if (ret_value == RET_ERROR) { if (BLI_rename(tempname, name) != 0) { BKE_reportf(reports, RPT_ERROR, "Error restoring temp file (check files '%s' '%s')", tempname, name); } } else { if (BLI_delete(tempname, false, false) != 0) { BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname); } } } if (guimode) {} //XXX waitcursor(0); return (ret_value); }
static void index_rebuild_fallback(struct anim * anim, IMB_Timecode_Type UNUSED(tcs_in_use), IMB_Proxy_Size proxy_sizes_in_use, int quality, short *stop, short *do_update, float *progress) { int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE); int i, pos; AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT]; char fname[FILE_MAXDIR+FILE_MAXFILE]; char fname_tmp[FILE_MAXDIR+FILE_MAXFILE]; memset(proxy_ctx, 0, sizeof(proxy_ctx)); /* since timecode indices only work with ffmpeg right now, don't know a sensible fallback here... so no proxies, no game to play... */ if (proxy_sizes_in_use == IMB_PROXY_NONE) { return; } for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { char fname[FILE_MAXDIR+FILE_MAXFILE]; get_proxy_filename(anim, proxy_sizes[i], fname, TRUE); BLI_make_existing_file(fname); proxy_ctx[i] = alloc_proxy_output_avi( anim, fname, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality); } } for (pos = 0; pos < cnt; pos++) { struct ImBuf * ibuf = IMB_anim_absolute( anim, pos, IMB_TC_NONE, IMB_PROXY_NONE); int next_progress = (int) ((double) pos / (double) cnt); if (*progress != next_progress) { *progress = next_progress; *do_update = 1; } if (*stop) { break; } IMB_flipy(ibuf); for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { int x = anim->x * proxy_fac[i]; int y = anim->y * proxy_fac[i]; struct ImBuf * s_ibuf = IMB_scalefastImBuf( ibuf, x, y); IMB_convert_rgba_to_abgr(s_ibuf); AVI_write_frame (proxy_ctx[i], pos, AVI_FORMAT_RGB32, s_ibuf->rect, x * y * 4); /* note that libavi free's the buffer... */ s_ibuf->rect = 0; IMB_freeImBuf(s_ibuf); } } } for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { AVI_close_compress (proxy_ctx[i]); MEM_freeN (proxy_ctx[i]); get_proxy_filename(anim, proxy_sizes[i], fname_tmp, TRUE); get_proxy_filename(anim, proxy_sizes[i], fname, FALSE); if (*stop) { unlink(fname_tmp); } else { rename(fname_tmp, fname); } } } }
static struct proxy_output_ctx * alloc_proxy_output_ffmpeg( struct anim * anim, AVStream * st, int proxy_size, int width, int height, int quality) { struct proxy_output_ctx * rv = MEM_callocN( sizeof(struct proxy_output_ctx), "alloc_proxy_output"); char fname[FILE_MAXDIR+FILE_MAXFILE]; // JPEG requires this width = round_up(width, 8); height = round_up(height, 8); rv->proxy_size = proxy_size; rv->anim = anim; get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE); BLI_make_existing_file(fname); rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname); fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename); rv->st = av_new_stream(rv->of, 0); rv->c = rv->st->codec; rv->c->codec_type = AVMEDIA_TYPE_VIDEO; rv->c->codec_id = CODEC_ID_MJPEG; rv->c->width = width; rv->c->height = height; rv->of->oformat->video_codec = rv->c->codec_id; rv->codec = avcodec_find_encoder(rv->c->codec_id); if (!rv->codec) { fprintf(stderr, "No ffmpeg MJPEG encoder available? " "Proxy not built!\n"); av_free(rv->of); return NULL; } if (rv->codec->pix_fmts) { rv->c->pix_fmt = rv->codec->pix_fmts[0]; } else { rv->c->pix_fmt = PIX_FMT_YUVJ420P; } rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->codec->sample_aspect_ratio; rv->c->time_base.den = 25; rv->c->time_base.num = 1; rv->st->time_base = rv->c->time_base; if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (av_set_parameters(rv->of, NULL) < 0) { fprintf(stderr, "Couldn't set output parameters? " "Proxy not built!\n"); av_free(rv->of); return 0; } if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Couldn't open outputfile! " "Proxy not built!\n"); av_free(rv->of); return 0; } avcodec_open(rv->c, rv->codec); rv->video_buffersize = 2000000; rv->video_buffer = (uint8_t*)MEM_mallocN( rv->video_buffersize, "FFMPEG video buffer"); rv->orig_height = st->codec->height; if (st->codec->width != width || st->codec->height != height || st->codec->pix_fmt != rv->c->pix_fmt) { rv->frame = avcodec_alloc_frame(); avpicture_fill((AVPicture*) rv->frame, MEM_mallocN(avpicture_get_size( rv->c->pix_fmt, round_up(width, 16), height), "alloc proxy output frame"), rv->c->pix_fmt, round_up(width, 16), height); rv->sws_ctx = sws_getContext( st->codec->width, st->codec->height, st->codec->pix_fmt, width, height, rv->c->pix_fmt, SWS_FAST_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); } av_write_header(rv->of); return rv; }
void ImagesExporter::export_UV_Image(Image *image, bool use_copies) { std::string name(id_name(image)); std::string translated_name(translate_id(name)); bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end(); if (not_yet_exported) { ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL); if (!imbuf) { fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name); return; } bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0; ImageFormatData imageFormat; BKE_imbuf_to_image_format(&imageFormat, imbuf); short image_source = image->source; bool is_generated = image_source == IMA_SRC_GENERATED; bool is_packed = image->packedfile != NULL; char export_path[FILE_MAX]; char source_path[FILE_MAX]; char export_dir[FILE_MAX]; char export_file[FILE_MAX]; // Destination folder for exported assets BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir)); if (is_generated || is_dirty || use_copies || is_packed) { // make absolute destination path BLI_strncpy(export_file, name.c_str(), sizeof(export_file)); BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat); BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file); // make dest directory if it doesn't exist BLI_make_existing_file(export_path); } if (is_generated || is_dirty || is_packed) { // This image in its current state only exists in Blender memory. // So we have to export it. The export will keep the image state intact, // so the exported file will not be associated with the image. if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) { fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path); return; } BLI_strncpy(export_path, export_file, sizeof(export_path)); } else { // make absolute source path BLI_strncpy(source_path, image->name, sizeof(source_path)); BLI_path_abs(source_path, G.main->name); BLI_cleanup_path(NULL, source_path); if (use_copies) { // This image is already located on the file system. // But we want to create copies here. // To move images into the same export directory. // Note: If an image is already located in the export folder, // then skip the copy (as it would result in a file copy error). if (BLI_path_cmp(source_path, export_path) != 0) { if (BLI_copy(source_path, export_path) != 0) { fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path); return; } } BLI_strncpy(export_path, export_file, sizeof(export_path)); } else { // Do not make any copies, but use the source path directly as reference // to the original image BLI_strncpy(export_path, source_path, sizeof(export_path)); } } COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */ img.add(mSW); fprintf(stdout, "Collada export: Added image: %s\n", export_file); mImages.push_back(translated_name); BKE_image_release_ibuf(image, imbuf, NULL); } }
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; }
int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfig = FLUID_SUFFIX_CONFIG; const char *suffixSurface = FLUID_SUFFIX_SURFACE; 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 float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; wmJob *steve; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); 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); } /* 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."); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldnt be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // 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 output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; /* ******** initialise and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); /* ---- XXX: No Time animation curve for now, leaving this code here for reference { int timeIcu[1] = { FLUIDSIM_TIME }; float timeDef[1] = { 1. }; // 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 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]; } fsset->} else { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; } } } // domain channel init */ /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if(!invert_m4_m4(invDomMat, domainMat)) { snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix."); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, dont overwrite/delete original file BLI_snprintf(targetFile, sizeof(targetFile), "%s%s.tmp", targetDir, suffixConfig); // make sure these directories exist as well if(outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_snprintf(targetFile, sizeof(targetFile), "%s%s", targetDir, 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; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; 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 domain transform matrix { int j; for(i=0; i<4; i++) { for(j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; /* setup job */ WM_jobs_customdata(steve, fb, fluidbake_free); WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), steve); /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }