diff options
author | Daniel Genrich <daniel.genrich@gmx.net> | 2009-07-30 19:00:26 +0400 |
---|---|---|
committer | Daniel Genrich <daniel.genrich@gmx.net> | 2009-07-30 19:00:26 +0400 |
commit | 58c88bcf7636abce291168af189284181f2f7033 (patch) | |
tree | f99c18e5601242113b0d3888331578d5b0966c59 /source | |
parent | 1b26fe50c35afe5c83a0bf3a69fce55db00374d3 (diff) |
BF2.5: First commit of smoke code.
Not working:
a) rendering (since volumterics branch is not merged yet)
b) moving collision objects of any kind
c) saving of collision objects (because that's what I am working on)
d) pointcache
e) A bunch of other things I already know of
So please do not report any bugs on this one yet :-)
Diffstat (limited to 'source')
21 files changed, 2475 insertions, 80 deletions
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h new file mode 100644 index 00000000000..b37e1d08fcc --- /dev/null +++ b/source/blender/blenkernel/BKE_smoke.h @@ -0,0 +1,55 @@ +/** + * BKE_cloth.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_SMOKE_H_ +#define BKE_SMOKE_H_ + +void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm); + +void smokeModifier_free (struct SmokeModifierData *smd); +void smokeModifier_reset(struct SmokeModifierData *smd); +void smokeModifier_createType(struct SmokeModifierData *smd); + +void smoke_set_tray(struct SmokeModifierData *smd, size_t index, float transparency); +float smoke_get_tray(struct SmokeModifierData *smd, size_t index); +float smoke_get_tvox(struct SmokeModifierData *smd, size_t index); +void smoke_set_tvox(struct SmokeModifierData *smd, size_t index, float tvox); + +void smoke_set_bigtray(struct SmokeModifierData *smd, size_t index, float transparency); +float smoke_get_bigtray(struct SmokeModifierData *smd, size_t index); +float smoke_get_bigtvox(struct SmokeModifierData *smd, size_t index); +void smoke_set_bigtvox(struct SmokeModifierData *smd, size_t index, float tvox); + +long long smoke_get_mem_req(int xres, int yres, int zres, int amplify); +void smoke_prepare_View(struct SmokeModifierData *smd, float *light); +void smoke_prepare_bigView(struct SmokeModifierData *smd, float *light); + +#endif /* BKE_SMOKE_H_ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 92cc206667c..656a292da15 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -32,7 +32,7 @@ SET(INC ../imbuf ../avi ../../../intern/elbeem/extern ../../../intern/opennl/extern ../../../intern/iksolver/extern ../blenloader ../quicktime ../../../extern/bullet2/src - ../nodes ../../../extern/glew/include ../gpu ../makesrna + ../nodes ../../../extern/glew/include ../gpu ../makesrna ../../../intern/smoke/extern ../../../intern/bsp/extern ${ZLIB_INC} ) diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index dbc990d0613..7016d992f02 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -10,6 +10,7 @@ incs += ' #/intern/iksolver/extern ../blenloader' incs += ' #/extern/bullet2/src' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' +incs += ' #/intern/smoke/extern' incs += ' ' + env['BF_OPENGL_INC'] incs += ' ' + env['BF_ZLIB_INC'] diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c129e8ed99b..8935d33b3bf 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -58,6 +58,7 @@ #include "DNA_cloth_types.h" #include "DNA_curve_types.h" #include "DNA_effect_types.h" +#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -67,6 +68,7 @@ #include "DNA_object_force.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_smoke_types.h" #include "DNA_texture_types.h" #include "BLI_editVert.h" @@ -96,6 +98,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_smoke.h" #include "BKE_softbody.h" #include "BKE_subsurf.h" #include "BKE_texture.h" @@ -5787,6 +5790,100 @@ static int softbodyModifier_dependsOnTime(ModifierData *md) return 1; } +/* Smoke */ + +static void smokeModifier_initData(ModifierData *md) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + + smd->domain = NULL; + smd->flow = NULL; + smd->coll = NULL; + smd->type = 0; + smd->time = -1; + + /* + smd->fluid = NULL; + smd->maxres = 48; + smd->amplify = 4; + smd->omega = 0.5; + smd->time = 0; + smd->flags = 0; + smd->noise = MOD_SMOKE_NOISEWAVE; + smd->visibility = 1; + + // init 3dview buffer + smd->tvox = NULL; + smd->tray = NULL; + smd->tvoxbig = NULL; + smd->traybig = NULL; + smd->viewsettings = 0; + smd->bind = NULL; + smd->max_textures = 0; + */ +} + +static void smokeModifier_freeData(ModifierData *md) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + + smokeModifier_free (smd); +} + +static void smokeModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + DerivedMesh *dm = NULL; + + if(derivedData) dm = derivedData; + else if(ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data, ob); + else return; + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smokeModifier_do(smd, md->scene, ob, dm); + + if(dm != derivedData) dm->release(dm); +} + +static int smokeModifier_dependsOnTime(ModifierData *md) +{ + return 1; +} + +static void smokeModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, + DagNode *obNode) +{ + SmokeModifierData *smd = (SmokeModifierData *) md; + /* + if(smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) + { + if(smd->domain->fluid_group) + { + GroupObject *go = NULL; + + for(go = smd->domain->fluid_group->gobject.first; go; go = go->next) + { + if(go->ob) + { + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke); + + // check for initialized smoke object + if(smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + { + DagNode *curNode = dag_get_node(forest, go->ob); + dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Smoke Flow"); + } + } + } + } + } + */ +} /* Cloth */ @@ -8477,6 +8574,15 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) | eModifierTypeFlag_Single; mti->deformVerts = softbodyModifier_deformVerts; mti->dependsOnTime = softbodyModifier_dependsOnTime; + + mti = INIT_TYPE(Smoke); + mti->type = eModifierTypeType_OnlyDeform; + mti->initData = smokeModifier_initData; + mti->freeData = smokeModifier_freeData; + mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->deformVerts = smokeModifier_deformVerts; + mti->dependsOnTime = smokeModifier_dependsOnTime; + mti->updateDepgraph = smokeModifier_updateDepgraph; mti = INIT_TYPE(Cloth); mti->type = eModifierTypeType_Nonconstructive; diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c new file mode 100644 index 00000000000..941381f04f3 --- /dev/null +++ b/source/blender/blenkernel/intern/smoke.c @@ -0,0 +1,1342 @@ +/** + * BKE_cloth.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <GL/glew.h> + +#include "MEM_guardedalloc.h" + +#include <float.h> +#include <math.h> +#include "stdio.h" + +#include "BLI_linklist.h" +#include "BLI_rand.h" +#include "BLI_jitter.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_edgehash.h" +#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_modifier.h" +#include "BKE_particle.h" +#include "BKE_utildefines.h" + +#include "DNA_customdata_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" +#include "DNA_smoke_types.h" + +#include "smoke_API.h" + +#include "BKE_smoke.h" + +#ifdef _WIN32 +#include <time.h> +#include <stdio.h> +#include <conio.h> +#include <windows.h> + +static LARGE_INTEGER liFrequency; +static LARGE_INTEGER liStartTime; +static LARGE_INTEGER liCurrentTime; + +static void tstart ( void ) +{ + QueryPerformanceFrequency ( &liFrequency ); + QueryPerformanceCounter ( &liStartTime ); +} +static void tend ( void ) +{ + QueryPerformanceCounter ( &liCurrentTime ); +} +static double tval() +{ + return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart )); +} +#else +#include <sys/time.h> +static struct timeval _tstart, _tend; +static struct timezone tz; +static void tstart ( void ) +{ + gettimeofday ( &_tstart, &tz ); +} +static void tend ( void ) +{ + gettimeofday ( &_tend,&tz ); +} +static double tval() +{ + double t1, t2; + t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 ); + t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 ); + return t2-t1; +} +#endif + +struct Object; +struct Scene; +struct DerivedMesh; +struct SmokeModifierData; + +// forward declerations +static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct); +static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct); +void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len); + +#define TRI_UVOFFSET (1./4.) + +int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) +{ + if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) + { + size_t i; + float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + float size[3]; + MVert *verts = dm->getVertArray(dm); + float scale = 0.0; + int res = smd->domain->maxres; + + // get BB of domain + for(i = 0; i < dm->getNumVerts(dm); i++) + { + float tmp[3]; + + VECCOPY(tmp, verts[i].co); + Mat4MulVecfl(ob->obmat, tmp); + + // min BB + min[0] = MIN2(min[0], tmp[0]); + min[1] = MIN2(min[1], tmp[1]); + min[2] = MIN2(min[2], tmp[2]); + + // max BB + max[0] = MAX2(max[0], tmp[0]); + max[1] = MAX2(max[1], tmp[1]); + max[2] = MAX2(max[2], tmp[2]); + } + + VECCOPY(smd->domain->p0, min); + VECCOPY(smd->domain->p1, max); + + // calc other res with max_res provided + VECSUB(size, max, min); + if(size[0] > size[1]) + { + if(size[0] > size[1]) + { + scale = res / size[0]; + smd->domain->dx = size[0] / res; + smd->domain->res[0] = res; + smd->domain->res[1] = (int)(size[1] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + else + { + scale = res / size[1]; + smd->domain->dx = size[1] / res; + smd->domain->res[1] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + } + else + { + if(size[1] > size[2]) + { + scale = res / size[1]; + smd->domain->dx = size[1] / res; + smd->domain->res[1] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + else + { + scale = res / size[2]; + smd->domain->dx = size[2] / res; + smd->domain->res[2] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[1] = (int)(size[1] * scale + 0.5); + } + } + + printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); + + // dt max is 0.1 + smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->amplify, smd->domain->p0, smd->domain->p1, 2.5 / FPS); + smd->time = scene->r.cfra; + smd->domain->firstframe = smd->time; + + smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta)); + + return 1; + } + else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) + { + // handle flow object here + // XXX TODO + + smd->time = scene->r.cfra; + + // update particle lifetime to be one frame + // smd->flow->psys->part->lifetime = scene->r.efra + 1; + + return 1; + } + else if((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) + { + smd->time = scene->r.cfra; + + if(!smd->coll->points) + { + // init collision points + SmokeCollSettings *scs = smd->coll; + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + size_t i = 0, divs = 0; + int *tridivs = NULL; + float cell_len = 1.0 / 50.0; // for res = 50 + size_t newdivs = 0; + size_t max_points = 0; + size_t quads = 0, facecounter = 0; + + // count quads + for(i = 0; i < dm->getNumFaces(dm); i++) + { + if(mface[i].v4) + quads++; + } + + calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len); + + // count triangle divisions + for(i = 0; i < dm->getNumFaces(dm) + quads; i++) + { + divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); + } + + // printf("divs: %d\n", divs); + + scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints"); + + for(i = 0; i < dm->getNumVerts(dm); i++) + { + float tmpvec[3]; + VECCOPY(tmpvec, mvert[i].co); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[i * 3], tmpvec); + } + + for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++) + { + int again = 0; + do + { + size_t j, k; + int divs1 = tridivs[3 * facecounter + 0]; + int divs2 = tridivs[3 * facecounter + 1]; + int divs3 = tridivs[3 * facecounter + 2]; + float side1[3], side2[3], trinormorg[3], trinorm[3]; + + if(again == 1 && mface[i].v4) + { + VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); + VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co); + } + else + { + VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co); + VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); + } + + Crossf(trinormorg, side1, side2); + Normalize(trinormorg); + VECCOPY(trinorm, trinormorg); + VecMulf(trinorm, 0.25 * cell_len); + + for(j = 0; j <= divs1; j++) + { + for(k = 0; k <= divs2; k++) + { + float p1[3], p2[3], p3[3], p[3]={0,0,0}; + const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0); + const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0); + float tmpvec[3]; + + if(uf+vf > 1.0) + { + // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2); + continue; + } + + VECCOPY(p1, mvert[ mface[i].v1 ].co); + if(again == 1 && mface[i].v4) + { + VECCOPY(p2, mvert[ mface[i].v3 ].co); + VECCOPY(p3, mvert[ mface[i].v4 ].co); + } + else + { + VECCOPY(p2, mvert[ mface[i].v2 ].co); + VECCOPY(p3, mvert[ mface[i].v3 ].co); + } + + VecMulf(p1, (1.0-uf-vf)); + VecMulf(p2, uf); + VecMulf(p3, vf); + + VECADD(p, p1, p2); + VECADD(p, p, p3); + + if(newdivs > divs) + printf("mem problem\n"); + + // mMovPoints.push_back(p + trinorm); + VECCOPY(tmpvec, p); + VECADD(tmpvec, tmpvec, trinorm); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); + newdivs++; + + if(newdivs > divs) + printf("mem problem\n"); + + // mMovPoints.push_back(p - trinorm); + VECCOPY(tmpvec, p); + VECSUB(tmpvec, tmpvec, trinorm); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); + newdivs++; + } + } + + if(again == 0 && mface[i].v4) + again++; + else + again = 0; + + facecounter++; + + } while(again!=0); + } + + scs->numpoints = dm->getNumVerts(dm) + newdivs; + + MEM_freeN(tridivs); + } + + } + + return 0; +} + +/*! init triangle divisions */ +void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) +{ + // mTriangleDivs1.resize( faces.size() ); + // mTriangleDivs2.resize( faces.size() ); + // mTriangleDivs3.resize( faces.size() ); + + size_t i = 0, facecounter = 0; + float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); + float maxpart = ABS(maxscale[0]); + float scaleFac = 0; + float fsTri = 0; + if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + scaleFac = 1.0 / maxpart; + // featureSize = mLevel[mMaxRefine].nodeSize + fsTri = cell_len * 0.5 * scaleFac; + + if(*tridivs) + MEM_freeN(*tridivs); + + *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); + + for(i = 0, facecounter = 0; i < numfaces; i++) + { + float p0[3], p1[3], p2[3]; + float side1[3]; + float side2[3]; + float side3[3]; + int divs1=0, divs2=0, divs3=0; + + VECCOPY(p0, verts[faces[i].v1].co); + Mat4MulVecfl (ob->obmat, p0); + VECCOPY(p1, verts[faces[i].v2].co); + Mat4MulVecfl (ob->obmat, p1); + VECCOPY(p2, verts[faces[i].v3].co); + Mat4MulVecfl (ob->obmat, p2); + + VECSUB(side1, p1, p0); + VECSUB(side2, p2, p0); + VECSUB(side3, p1, p2); + + if(INPR(side1, side1) > fsTri*fsTri) + { + float tmp = Normalize(side1); + divs1 = (int)(tmp/fsTri); + } + if(INPR(side2, side2) > fsTri*fsTri) + { + float tmp = Normalize(side2); + divs2 = (int)(tmp/fsTri); + + /* + // debug + if(i==0) + printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); + */ + } + + (*tridivs)[3 * facecounter + 0] = divs1; + (*tridivs)[3 * facecounter + 1] = divs2; + (*tridivs)[3 * facecounter + 2] = divs3; + + // TODO quad case + if(faces[i].v4) + { + divs1=0, divs2=0, divs3=0; + + facecounter++; + + VECCOPY(p1, verts[faces[i].v3].co); + Mat4MulVecfl (ob->obmat, p1); + VECCOPY(p2, verts[faces[i].v4].co); + Mat4MulVecfl (ob->obmat, p2); + + VECSUB(side1, p1, p0); + VECSUB(side2, p2, p0); + VECSUB(side3, p1, p2); + + if(INPR(side1, side1) > fsTri*fsTri) + { + float tmp = Normalize(side1); + divs1 = (int)(tmp/fsTri); + } + if(INPR(side2, side2) > fsTri*fsTri) + { + float tmp = Normalize(side2); + divs2 = (int)(tmp/fsTri); + } + + (*tridivs)[3 * facecounter + 0] = divs1; + (*tridivs)[3 * facecounter + 1] = divs2; + (*tridivs)[3 * facecounter + 2] = divs3; + } + facecounter++; + } +} + +void smokeModifier_freeDomain(SmokeModifierData *smd) +{ + if(smd->domain) + { + // free visualisation buffers + if(smd->domain->bind) + { + glDeleteTextures(smd->domain->max_textures, smd->domain->bind); + MEM_freeN(smd->domain->bind); + } + smd->domain->max_textures = 0; // unnecessary but let's be sure + + if(smd->domain->tray) + MEM_freeN(smd->domain->tray); + if(smd->domain->tvox) + MEM_freeN(smd->domain->tvox); + if(smd->domain->traybig) + MEM_freeN(smd->domain->traybig); + if(smd->domain->tvoxbig) + MEM_freeN(smd->domain->tvoxbig); + + if(smd->domain->fluid) + { + smoke_free(smd->domain->fluid); + } + MEM_freeN(smd->domain); + smd->domain = NULL; + } +} + +void smokeModifier_freeFlow(SmokeModifierData *smd) +{ + if(smd->flow) + { + MEM_freeN(smd->flow); + smd->flow = NULL; + } +} + +void smokeModifier_freeCollision(SmokeModifierData *smd) +{ + if(smd->coll) + { + if(smd->coll->points) + { + MEM_freeN(smd->coll->points); + smd->coll->points = NULL; + } + + MEM_freeN(smd->coll); + smd->coll = NULL; + } +} + +void smokeModifier_reset(struct SmokeModifierData *smd) +{ + if(smd) + { + if(smd->domain) + { + // free visualisation buffers + if(smd->domain->bind) + { + glDeleteTextures(smd->domain->max_textures, smd->domain->bind); + MEM_freeN(smd->domain->bind); + smd->domain->bind = NULL; + } + smd->domain->max_textures = 0; + smd->domain->viewsettings = 0; // reset view for new frame + + if(smd->domain->tray) + MEM_freeN(smd->domain->tray); + if(smd->domain->tvox) + MEM_freeN(smd->domain->tvox); + if(smd->domain->traybig) + MEM_freeN(smd->domain->traybig); + if(smd->domain->tvoxbig) + MEM_freeN(smd->domain->tvoxbig); + + smd->domain->tvox = NULL; + smd->domain->tray = NULL; + smd->domain->tvoxbig = NULL; + smd->domain->traybig = NULL; + + if(smd->domain->fluid) + { + smoke_free(smd->domain->fluid); + smd->domain->fluid = NULL; + } + } + else if(smd->flow) + { + + } + else if(smd->coll) + { + if(smd->coll->points) + { + MEM_freeN(smd->coll->points); + smd->coll->points = NULL; + } + } + } +} + +void smokeModifier_free (SmokeModifierData *smd) +{ + if(smd) + { + smokeModifier_freeDomain(smd); + smokeModifier_freeFlow(smd); + smokeModifier_freeCollision(smd); + } +} + +void smokeModifier_createType(struct SmokeModifierData *smd) +{ + if(smd) + { + if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { + if(smd->domain) + smokeModifier_freeDomain(smd); + + smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); + + smd->domain->smd = smd; + + /* set some standard values */ + smd->domain->fluid = NULL; + smd->domain->eff_group = NULL; + smd->domain->fluid_group = NULL; + smd->domain->coll_group = NULL; + smd->domain->maxres = 48; + smd->domain->amplify = 4; + smd->domain->omega = 0.5; + smd->domain->alpha = -0.001; + smd->domain->beta = 0.1; + smd->domain->flags = 0; + smd->domain->noise = MOD_SMOKE_NOISEWAVE; + smd->domain->visibility = 1; + + // init 3dview buffer + smd->domain->tvox = NULL; + smd->domain->tray = NULL; + smd->domain->tvoxbig = NULL; + smd->domain->traybig = NULL; + smd->domain->viewsettings = 0; + smd->domain->bind = NULL; + smd->domain->max_textures = 0; + } + else if(smd->type & MOD_SMOKE_TYPE_FLOW) + { + if(smd->flow) + smokeModifier_freeFlow(smd); + + smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); + + smd->flow->smd = smd; + + /* set some standard values */ + smd->flow->density = 1.0; + smd->flow->temp = 1.0; + + smd->flow->psys = NULL; + + } + else if(smd->type & MOD_SMOKE_TYPE_COLL) + { + if(smd->coll) + smokeModifier_freeCollision(smd); + + smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); + + smd->coll->smd = smd; + smd->coll->points = NULL; + smd->coll->numpoints = 0; + } + } +} + +// forward declaration +void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big); + +void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +{ + int new = 0; + + if(scene->r.cfra >= smd->time) + smokeModifier_init(smd, ob, scene, dm); + + if((smd->type & MOD_SMOKE_TYPE_FLOW)) + { + if(scene->r.cfra > smd->time) + { + // XXX TODO + } + else if(scene->r.cfra < smd->time) + { + smd->time = scene->r.cfra; + smokeModifier_reset(smd); + } + } + else if((smd->type & MOD_SMOKE_TYPE_DOMAIN)) + { + SmokeDomainSettings *sds = smd->domain; + + if(scene->r.cfra > smd->time) + { + GroupObject *go = NULL; + Base *base = NULL; + int cnt_domain = 0; + + tstart(); + + sds->viewsettings = 0; // reset view for new frame + + // check for 2nd domain, if not there -> no groups are necessary + for(base = scene->base.first; base; base= base->next) + { + Object *ob1= base->object; + + if(ob1 && ob1 != ob) + { + ModifierData *tmd = modifiers_findByType(ob1, eModifierType_Smoke); + + if(tmd && tmd->mode & (eModifierMode_Realtime | eModifierMode_Render)) + { + SmokeModifierData *tsmd = (SmokeModifierData *)tmd; + + if((tsmd->type & MOD_SMOKE_TYPE_DOMAIN)) + { + cnt_domain++; + } + } + } + } + + // do flows and fluids + if(sds->fluid_group || !cnt_domain) + { + Object *otherobj = NULL; + ModifierData *md = NULL; + + if(cnt_domain && !sds->fluid_group) // we use groups since we have 2 domains + go = sds->fluid_group->gobject.first; + else + base = scene->base.first; + + while(base || go) + { + otherobj = NULL; + + if(cnt_domain && !sds->fluid_group) + { + if(go->ob) + otherobj = go->ob; + } + else + otherobj = base->object; + + if(!otherobj) + { + if(cnt_domain && !sds->fluid_group) + go = go->next; + else + base= base->next; + + continue; + } + + md = modifiers_findByType(otherobj, eModifierType_Smoke); + + // check for active smoke modifier + if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + { + SmokeModifierData *smd2 = (SmokeModifierData *)md; + + // check for initialized smoke object + if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + { + // we got nice flow object + SmokeFlowSettings *sfs = smd2->flow; + + if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected + { + ParticleSystem *psys = sfs->psys; + ParticleSettings *part=psys->part; + ParticleData *pa = NULL; + int p = 0; + float *density = smoke_get_density(sds->fluid); + float *bigdensity = smoke_get_bigdensity(sds->fluid); + float *heat = smoke_get_heat(sds->fluid); + float *velocity_x = smoke_get_velocity_x(sds->fluid); + float *velocity_y = smoke_get_velocity_y(sds->fluid); + float *velocity_z = smoke_get_velocity_z(sds->fluid); + int bigres[3]; + + smoke_get_bigres(smd->domain->fluid, bigres); + + // mostly copied from particle code + for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++) + { + int cell[3]; + int valid = 1; + size_t i = 0; + size_t index = 0; + + if(pa->alive == PARS_KILLED) continue; + else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue; + else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue; + else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; + + // VECCOPY(pos, pa->state.co); + // Mat4MulVecfl (ob->imat, pos); + + // 1. get corresponding cell + get_cell(smd, pa->state.co, cell, 0); + + // check if cell is valid (in the domain boundary) + for(i = 0; i < 3; i++) + if((cell[i] > sds->res[i] - 1) || (cell[i] < 0)) + valid = 0; + + if(!valid) + continue; + + // 2. set cell values (heat, density and velocity) + index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2], sds->res[2]); + + heat[index] = sfs->temp; + density[index] = sfs->density; + velocity_x[index] = pa->state.vel[0]; + velocity_y[index] = pa->state.vel[1]; + velocity_z[index] = pa->state.vel[2]; + + // we need different handling for the high-res feature + if(bigdensity) + { + // init all surrounding cells according to amplification, too + int i, j, k; + for(i = 0; i < smd->domain->amplify; i++) + for(j = 0; j < smd->domain->amplify; j++) + for(k = 0; k < smd->domain->amplify; k++) + { + index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k, bigres[2]); + bigdensity[index] = sfs->density; + } + } + } + } + } + } + + if(cnt_domain && !sds->fluid_group) + go = go->next; + else + base= base->next; + } + } + + // do effectors + /* + if(sds->eff_group) + { + for(go = sds->eff_group->gobject.first; go; go = go->next) + { + if(go->ob) + { + if(ob->pd) + { + + } + } + } + } + */ + + // do collisions + if(sds->coll_group || !cnt_domain) + { + Object *otherobj = NULL; + ModifierData *md = NULL; + + if(cnt_domain && !sds->coll_group) // we use groups since we have 2 domains + go = sds->coll_group->gobject.first; + else + base = scene->base.first; + + while(base || go) + { + otherobj = NULL; + + if(cnt_domain && !sds->coll_group) + { + if(go->ob) + otherobj = go->ob; + } + else + otherobj = base->object; + + if(!otherobj) + { + if(cnt_domain && !sds->coll_group) + go = go->next; + else + base= base->next; + + continue; + } + + md = modifiers_findByType(otherobj, eModifierType_Smoke); + + // check for active smoke modifier + if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + { + SmokeModifierData *smd2 = (SmokeModifierData *)md; + + if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) + { + // we got nice collision object + SmokeCollSettings *scs = smd2->coll; + int cell[3]; + int valid = 1; + size_t index = 0; + size_t i, j; + unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); + + for(i = 0; i < scs->numpoints; i++) + { + // 1. get corresponding cell + get_cell(smd, &scs->points[3 * i], cell, 0); + + // check if cell is valid (in the domain boundary) + for(j = 0; j < 3; j++) + if((cell[j] > sds->res[j] - 1) || (cell[j] < 0)) + valid = 0; + + if(!valid) + continue; + + // 2. set cell values (heat, density and velocity) + index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2], sds->res[2]); + + obstacles[index] = 1; + + /* + const LbmFloat maxVelVal = 0.1666; + const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; + + LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { + const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; + USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); + if(usqr>maxusqr) { + // cutoff at maxVelVal + for(int jj=0; jj<3; jj++) { + if(objvel[jj]>0.) objvel[jj] = maxVelVal; + if(objvel[jj]<0.) objvel[jj] = -maxVelVal; + } + } } + + const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); + const LbmVec oldov=objvel; // debug + objvel = vec2L((*pNormals)[n]) *dp; + */ + } + } + } + + if(cnt_domain && !sds->coll_group) + go = go->next; + else + base= base->next; + } + } + + // set new time + smd->time = scene->r.cfra; + + // simulate the actual smoke (c++ code in intern/smoke) + smoke_step(sds->fluid); + + tend(); + printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); + } + else if(scene->r.cfra < smd->time) + { + // we got back in time, reset smoke in this case (TODO: use cache later) + smd->time = scene->r.cfra; + smokeModifier_reset(smd); + } + } +} + +// update necessary information for 3dview +void smoke_prepare_View(SmokeModifierData *smd, float *light) +{ + float *density = NULL; + size_t i = 0; + int x, y, z; + + if(!smd->domain->tray) + { + // TRay is for self shadowing + smd->domain->tray = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tRay"); + } + if(!smd->domain->tvox) + { + // TVox is for tranaparency + smd->domain->tvox = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tVox"); + } + + // update 3dview + density = smoke_get_density(smd->domain->fluid); + for(x = 0; x < smd->domain->res[0]; x++) + for(y = 0; y < smd->domain->res[1]; y++) + for(z = 0; z < smd->domain->res[2]; z++) + { + size_t index; + + index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z, smd->domain->res[2]); + // Transparency computation + // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4 + // T_vox = exp(-C_ext * h) + // C_ext/sigma_t = density * C_ext + smoke_set_tvox(smd, index, exp(-density[index] * smd->domain->dx)); + } + smoke_calc_transparency(smd, light, 0); +} + +// update necessary information for 3dview ("high res" option) +void smoke_prepare_bigView(SmokeModifierData *smd, float *light) +{ + float *density = NULL; + size_t i = 0; + int bigres[3]; + + smoke_get_bigres(smd->domain->fluid, bigres); + + if(!smd->domain->traybig) + { + // TRay is for self shadowing + smd->domain->traybig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tRayBig"); + } + if(!smd->domain->tvoxbig) + { + // TVox is for tranaparency + smd->domain->tvoxbig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tVoxBig"); + } + + density = smoke_get_bigdensity(smd->domain->fluid); + for (i = 0; i < bigres[0] * bigres[1] * bigres[2]; i++) + { + // Transparency computation + // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4 + // T_vox = exp(-C_ext * h) + // C_ext/sigma_t = density * C_ext + smoke_set_bigtvox(smd, i, exp(-density[i] * smd->domain->dx / smd->domain->amplify) ); + } + smoke_calc_transparency(smd, light, 1); +} + + +float smoke_get_tvox(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tvox[index]; +} + +void smoke_set_tvox(SmokeModifierData *smd, size_t index, float tvox) +{ + smd->domain->tvox[index] = tvox; +} + +float smoke_get_tray(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tray[index]; +} + +void smoke_set_tray(SmokeModifierData *smd, size_t index, float transparency) +{ + smd->domain->tray[index] = transparency; +} + +float smoke_get_bigtvox(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tvoxbig[index]; +} + +void smoke_set_bigtvox(SmokeModifierData *smd, size_t index, float tvox) +{ + smd->domain->tvoxbig[index] = tvox; +} + +float smoke_get_bigtray(SmokeModifierData *smd, size_t index) +{ + return smd->domain->traybig[index]; +} + +void smoke_set_bigtray(SmokeModifierData *smd, size_t index, float transparency) +{ + smd->domain->traybig[index] = transparency; +} + +long long smoke_get_mem_req(int xres, int yres, int zres, int amplify) +{ + int totalCells = xres * yres * zres; + int amplifiedCells = totalCells * amplify * amplify * amplify; + + // print out memory requirements + long long int coarseSize = sizeof(float) * totalCells * 22 + + sizeof(unsigned char) * totalCells; + + long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids + sizeof(float) * totalCells * 8 + // small grids + sizeof(float) * 128 * 128 * 128; // noise tile + + long long int totalMB = (coarseSize + fineSize) / (1024 * 1024); + + return totalMB; +} + + +static void calc_voxel_transp(SmokeModifierData *smd, int *pixel, float *tRay) +{ + // printf("Pixel(%d, %d, %d)\n", pixel[0], pixel[1], pixel[2]); + const size_t index = smoke_get_index(pixel[0], smd->domain->res[0], pixel[1], smd->domain->res[1], pixel[2], smd->domain->res[2]); + + // T_ray *= T_vox + *tRay *= smoke_get_tvox(smd, index); +} + +static void calc_voxel_transp_big(SmokeModifierData *smd, int *pixel, float *tRay) +{ + int bigres[3]; + size_t index; + + smoke_get_bigres(smd->domain->fluid, bigres); + index = smoke_get_index(pixel[0], bigres[0], pixel[1], bigres[1], pixel[2], bigres[2]); + + /* + if(index > bigres[0]*bigres[1]*bigres[2]) + printf("pixel[0]: %d, [1]: %d, [2]: %d\n", pixel[0], pixel[1], pixel[2]); + */ + + // T_ray *= T_vox + *tRay *= smoke_get_bigtvox(smd, index); +} + +static void bresenham_linie_3D(SmokeModifierData *smd, int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, int big) +{ + int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; + int pixel[3]; + + pixel[0] = x1; + pixel[1] = y1; + pixel[2] = z1; + + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + + x_inc = (dx < 0) ? -1 : 1; + l = abs(dx); + y_inc = (dy < 0) ? -1 : 1; + m = abs(dy); + z_inc = (dz < 0) ? -1 : 1; + n = abs(dz); + dx2 = l << 1; + dy2 = m << 1; + dz2 = n << 1; + + if ((l >= m) && (l >= n)) { + err_1 = dy2 - l; + err_2 = dz2 - l; + for (i = 0; i < l; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(tRay < 0) + return; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + pixel[0] += x_inc; + } + } else if ((m >= l) && (m >= n)) { + err_1 = dx2 - m; + err_2 = dz2 - m; + for (i = 0; i < m; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(tRay < 0) + return; + if (err_1 > 0) { + pixel[0] += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + pixel[1] += y_inc; + } + } else { + err_1 = dy2 - n; + err_2 = dx2 - n; + for (i = 0; i < n; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(tRay < 0) + return; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + pixel[0] += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + pixel[2] += z_inc; + } + } + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); +} + +static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct) +{ + float tmp[3]; + + VECSUB(tmp, pos, smd->domain->p0); + VecMulf(tmp, 1.0 / smd->domain->dx); + + if(correct) + { + cell[0] = MIN2(smd->domain->res[0] - 1, MAX2(0, (int)(tmp[0] + 0.5))); + cell[1] = MIN2(smd->domain->res[1] - 1, MAX2(0, (int)(tmp[1] + 0.5))); + cell[2] = MIN2(smd->domain->res[2] - 1, MAX2(0, (int)(tmp[2] + 0.5))); + } + else + { + cell[0] = (int)(tmp[0] + 0.5); + cell[1] = (int)(tmp[1] + 0.5); + cell[2] = (int)(tmp[2] + 0.5); + } +} +static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct) +{ + float tmp[3]; + int res[3]; + smoke_get_bigres(smd->domain->fluid, res); + + VECSUB(tmp, pos, smd->domain->p0); + + VecMulf(tmp, smd->domain->amplify / smd->domain->dx ); + + if(correct) + { + cell[0] = MIN2(res[0] - 1, MAX2(0, (int)(tmp[0] + 0.5))); + cell[1] = MIN2(res[1] - 1, MAX2(0, (int)(tmp[1] + 0.5))); + cell[2] = MIN2(res[2] - 1, MAX2(0, (int)(tmp[2] + 0.5))); + } + else + { + cell[0] = (int)(tmp[0] + 0.5); + cell[1] = (int)(tmp[1] + 0.5); + cell[2] = (int)(tmp[2] + 0.5); + } +} + + +void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big) +{ + int x, y, z; + float bv[6]; + int res[3]; + float bigfactor = 1.0; + + // x + bv[0] = smd->domain->p0[0]; + bv[1] = smd->domain->p1[0]; + // y + bv[2] = smd->domain->p0[1]; + bv[3] = smd->domain->p1[1]; + // z + bv[4] = smd->domain->p0[2]; + bv[5] = smd->domain->p1[2]; +/* + printf("bv[0]: %f, [1]: %f, [2]: %f, [3]: %f, [4]: %f, [5]: %f\n", bv[0], bv[1], bv[2], bv[3], bv[4], bv[5]); + + printf("p0[0]: %f, p0[1]: %f, p0[2]: %f\n", smd->domain->p0[0], smd->domain->p0[1], smd->domain->p0[2]); + printf("p1[0]: %f, p1[1]: %f, p1[2]: %f\n", smd->domain->p1[0], smd->domain->p1[1], smd->domain->p1[2]); + printf("dx: %f, amp: %d\n", smd->domain->dx, smd->domain->amplify); +*/ + if(!big) + { + res[0] = smd->domain->res[0]; + res[1] = smd->domain->res[1]; + res[2] = smd->domain->res[2]; + } + else + { + smoke_get_bigres(smd->domain->fluid, res); + bigfactor = 1.0 / smd->domain->amplify; + } + +#pragma omp parallel for schedule(static) private(y, z) shared(big, smd, light, res, bigfactor) + for(x = 0; x < res[0]; x++) + for(y = 0; y < res[1]; y++) + for(z = 0; z < res[2]; z++) + { + float voxelCenter[3]; + size_t index; + float pos[3]; + int cell[3]; + float tRay = 1.0; + + index = smoke_get_index(x, res[0], y, res[1], z, res[2]); + + // voxelCenter = m_voxelarray[i].GetCenter(); + voxelCenter[0] = smd->domain->p0[0] + smd->domain->dx * bigfactor * x + smd->domain->dx * bigfactor * 0.5; + voxelCenter[1] = smd->domain->p0[1] + smd->domain->dx * bigfactor * y + smd->domain->dx * bigfactor * 0.5; + voxelCenter[2] = smd->domain->p0[2] + smd->domain->dx * bigfactor * z + smd->domain->dx * bigfactor * 0.5; + + // printf("vc[0]: %f, vc[1]: %f, vc[2]: %f\n", voxelCenter[0], voxelCenter[1], voxelCenter[2]); + // printf("light[0]: %f, light[1]: %f, light[2]: %f\n", light[0], light[1], light[2]); + + // get starting position (in voxel coords) + if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) + { + // we're ouside + // printf("out: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", pos[0], pos[1], pos[2]); + if(!big) + get_cell(smd, pos, cell, 1); + else + get_bigcell(smd, pos, cell, 1); + } + else + { + // printf("in: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", light[0], light[1], light[2]); + // we're inside + if(!big) + get_cell(smd, light, cell, 1); + else + get_bigcell(smd, light, cell, 1); + } + + // printf("cell - [0]: %d, [1]: %d, [2]: %d\n", cell[0], cell[1], cell[2]); + bresenham_linie_3D(smd, cell[0], cell[1], cell[2], x, y, z, &tRay, big); + + if(!big) + smoke_set_tray(smd, index, tRay); + else + smoke_set_bigtray(smd, index, tRay); + } +} + diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index e3591a84e98..50462d531ef 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -93,5 +93,7 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); +float BLI_bvhtree_bb_raycast(float *bv, float *light_start, float *light_end, float *pos); + #endif // BLI_KDOPBVH_H diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 0f8194362c9..84de9f9d862 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -72,10 +72,10 @@ struct BVHTree char start_axis, stop_axis; // KDOP_AXES array indices according to axis }; -typedef struct BVHOverlapData -{ - BVHTree *tree1, *tree2; - BVHTreeOverlap *overlap; +typedef struct BVHOverlapData +{ + BVHTree *tree1, *tree2; + BVHTreeOverlap *overlap; int i, max_overlap; /* i is number of overlaps */ int start_axis, stop_axis; } BVHOverlapData; @@ -109,7 +109,7 @@ typedef struct BVHRayCastData //////////////////////////////////////////////////////////////////////// // Bounding Volume Hierarchy Definition -// +// // Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below // Notes: You have to choose the type at compile time ITM // Notes: You can choose the tree type --> binary, quad, octree, choose below @@ -188,10 +188,10 @@ int ADJUST_MEMORY(void *local_memblock, void **memblock, int new_size, int *max_ ////////////////////////////////////////////////////////////////////////////////////////////////////// -// Introsort +// Introsort // with permission deriven from the following Java code: // http://ralphunden.net/content/tutorials/a-guide-to-introsort/ -// and he derived it from the SUN STL +// and he derived it from the SUN STL ////////////////////////////////////////////////////////////////////////////////////////////////////// static int size_threshold = 16; /* @@ -362,7 +362,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi float newminmax; float *bv = node->bv; int i, k; - + // don't init boudings for the moving case if(!moving) { @@ -372,7 +372,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi bv[2*i + 1] = -FLT_MAX; } } - + for(k = 0; k < numpoints; k++) { // for all Axes. @@ -394,7 +394,7 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) int i, j; float *bv = node->bv; - + for (i = tree->start_axis; i < tree->stop_axis; i++) { bv[2*i] = FLT_MAX; @@ -406,10 +406,10 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) // for all Axes. for (i = tree->start_axis; i < tree->stop_axis; i++) { - newmin = tree->nodes[j]->bv[(2 * i)]; + newmin = tree->nodes[j]->bv[(2 * i)]; if ((newmin < bv[(2 * i)])) bv[(2 * i)] = newmin; - + newmax = tree->nodes[j]->bv[(2 * i) + 1]; if ((newmax > bv[(2 * i) + 1])) bv[(2 * i) + 1] = newmax; @@ -427,14 +427,14 @@ static char get_largest_axis(float *bv) middle_point[0] = (bv[1]) - (bv[0]); // x axis middle_point[1] = (bv[3]) - (bv[2]); // y axis middle_point[2] = (bv[5]) - (bv[4]); // z axis - if (middle_point[0] > middle_point[1]) + if (middle_point[0] > middle_point[1]) { if (middle_point[0] > middle_point[2]) return 1; // max x axis else return 5; // max z axis } - else + else { if (middle_point[1] > middle_point[2]) return 3; // max y axis @@ -448,24 +448,24 @@ static char get_largest_axis(float *bv) static void node_join(BVHTree *tree, BVHNode *node) { int i, j; - + for (i = tree->start_axis; i < tree->stop_axis; i++) { node->bv[2*i] = FLT_MAX; node->bv[2*i + 1] = -FLT_MAX; } - + for (i = 0; i < tree->tree_type; i++) { - if (node->children[i]) + if (node->children[i]) { for (j = tree->start_axis; j < tree->stop_axis; j++) { - // update minimum - if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) + // update minimum + if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) node->bv[(2 * j)] = node->children[i]->bv[(2 * j)]; - - // update maximum + + // update maximum if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1]) node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1]; } @@ -518,7 +518,7 @@ static void bvhtree_info(BVHTree *tree) static void verify_tree(BVHTree *tree) { int i, j, check = 0; - + // check the pointer list for(i = 0; i < tree->totleaf; i++) { @@ -538,7 +538,7 @@ static void verify_tree(BVHTree *tree) check = 0; } } - + // check the leaf list for(i = 0; i < tree->totleaf; i++) { @@ -558,7 +558,7 @@ static void verify_tree(BVHTree *tree) check = 0; } } - + printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf); } #endif @@ -703,7 +703,7 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHBuildHelper data; int depth; - + // set parent from root node to NULL BVHNode *tmp = branches_array+0; tmp->parent = NULL; @@ -722,7 +722,7 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, } branches_array--; //Implicit trees use 1-based indexs - + build_implicit_tree_helper(tree, &data); //Loop tree levels (log N) loops @@ -806,11 +806,11 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) { BVHTree *tree; int numnodes, i; - + // theres not support for trees below binary-trees :P if(tree_type < 2) return NULL; - + if(tree_type > MAX_TREETYPE) return NULL; @@ -820,13 +820,13 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) //so that tangent rays can still hit a bounding volume.. //this bug would show up when casting a ray aligned with a kdop-axis and with an edge of 2 faces epsilon = MAX2(FLT_EPSILON, epsilon); - + if(tree) { tree->epsilon = epsilon; - tree->tree_type = tree_type; + tree->tree_type = tree_type; tree->axis = axis; - + if(axis == 26) { tree->start_axis = 0; @@ -863,13 +863,13 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type; tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes"); - + if(!tree->nodes) { MEM_freeN(tree); return NULL; } - + tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV"); if(!tree->nodebv) { @@ -886,7 +886,7 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) } tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray"); - + if(!tree->nodearray) { MEM_freeN(tree->nodechild); @@ -902,14 +902,14 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) tree->nodearray[i].bv = tree->nodebv + i * axis; tree->nodearray[i].children = tree->nodechild + i * tree_type; } - + } return tree; } void BLI_bvhtree_free(BVHTree *tree) -{ +{ if(tree) { MEM_freeN(tree->nodes); @@ -946,27 +946,27 @@ int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints) { int i; BVHNode *node = NULL; - + // insert should only possible as long as tree->totbranch is 0 if(tree->totbranch > 0) return 0; - + if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes))) return 0; - + // TODO check if have enough nodes in array - + node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); tree->totleaf++; - + create_kdop_hull(tree, node, co, numpoints, 0); node->index= index; - + // inflate the bv with some epsilon for (i = tree->start_axis; i < tree->stop_axis; i++) { - node->bv[(2 * i)] -= tree->epsilon; // minimum - node->bv[(2 * i) + 1] += tree->epsilon; // maximum + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum } return 1; @@ -978,23 +978,23 @@ int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_movin { int i; BVHNode *node= NULL; - + // check if index exists if(index > tree->totleaf) return 0; - + node = tree->nodearray + index; - + create_kdop_hull(tree, node, co, numpoints, 0); - + if(co_moving) create_kdop_hull(tree, node, co_moving, numpoints, 1); - + // inflate the bv with some epsilon for (i = tree->start_axis; i < tree->stop_axis; i++) { - node->bv[(2 * i)] -= tree->epsilon; // minimum - node->bv[(2 * i) + 1] += tree->epsilon; // maximum + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum } return 1; @@ -1030,24 +1030,24 @@ static int tree_overlap(BVHNode *node1, BVHNode *node2, int start_axis, int stop float *bv2 = node2->bv; float *bv1_end = bv1 + (stop_axis<<1); - + bv1 += start_axis<<1; bv2 += start_axis<<1; - + // test all axis if min + max overlap for (; bv1 != bv1_end; bv1+=2, bv2+=2) { - if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1))) + if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1))) return 0; } - + return 1; } static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) { int j; - + if(tree_overlap(node1, node2, data->start_axis, data->stop_axis)) { // check if node1 is a leaf @@ -1056,17 +1056,17 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) // check if node2 is a leaf if(!node2->totnode) { - + if(node1 == node2) { return; } - + if(data->i >= data->max_overlap) - { + { // try to make alloc'ed memory bigger data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2); - + if(!data->overlap) { printf("Out of Memory in traverse\n"); @@ -1074,7 +1074,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) } data->max_overlap *= 2; } - + // both leafs, insert overlap! data->overlap[data->i].indexA = node1->index; data->overlap[data->i].indexB = node2->index; @@ -1092,7 +1092,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) } else { - + for(j = 0; j < data->tree2->tree_type; j++) { if(node1->children[j]) @@ -1108,21 +1108,21 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) int j, total = 0; BVHTreeOverlap *overlap = NULL, *to = NULL; BVHOverlapData **data; - + // check for compatibility of both trees (can't compare 14-DOP with 18-DOP) if((tree1->axis != tree2->axis) && (tree1->axis == 14 || tree2->axis == 14) && (tree1->axis == 18 || tree2->axis == 18)) return 0; - + // fast check root nodes for collision before doing big splitting + traversal if(!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis))) return 0; data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star"); - + for(j = 0; j < tree1->tree_type; j++) { data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData"); - + // init BVHOverlapData data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf)); data[j]->tree1 = tree1; @@ -1138,25 +1138,25 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) { traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]); } - + for(j = 0; j < tree1->tree_type; j++) total += data[j]->i; - + to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap"); - + for(j = 0; j < tree1->tree_type; j++) { memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap)); to+=data[j]->i; } - + for(j = 0; j < tree1->tree_type; j++) { free(data[j]->overlap); MEM_freeN(data[j]); } MEM_freeN(data); - + (*result) = total; return overlap; } @@ -1339,7 +1339,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node) push_heaps++; } } - + if(heap_size == 0) break; current = heap[0]; @@ -1405,10 +1405,9 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea */ //Determines the distance that the ray must travel to hit the bounding volume of the given node -static float ray_nearest_hit(BVHRayCastData *data, BVHNode *node) +static float ray_nearest_hit(BVHRayCastData *data, float *bv) { int i; - const float *bv = node->bv; float low = 0, upper = data->hit.dist; @@ -1436,7 +1435,7 @@ static float ray_nearest_hit(BVHRayCastData *data, BVHNode *node) if(lu > low) low = lu; if(ll < upper) upper = ll; } - + if(low > upper) return FLT_MAX; } } @@ -1449,7 +1448,7 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node) //ray-bv is really fast.. and simple tests revealed its worth to test it //before calling the ray-primitive functions - float dist = ray_nearest_hit(data, node); + float dist = ray_nearest_hit(data, node->bv); if(dist >= data->hit.dist) return; if(node->totnode == 0) @@ -1527,3 +1526,35 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float return data.hit.index; } +float BLI_bvhtree_bb_raycast(float *bv, float *light_start, float *light_end, float *pos) +{ + BVHRayCastData data; + float dist = 0.0; + int i; + + data.hit.dist = FLT_MAX; + + // get light direction + data.ray.direction[0] = light_end[0] - light_start[0]; + data.ray.direction[1] = light_end[1] - light_start[1]; + data.ray.direction[2] = light_end[2] - light_start[2]; + + data.ray.radius = 0.0; + + data.ray.origin[0] = light_start[0]; + data.ray.origin[1] = light_start[1]; + data.ray.origin[2] = light_start[2]; + + Normalize(data.ray.direction); + VECCOPY(data.ray_dot_axis, data.ray.direction); + + dist = ray_nearest_hit(&data, bv); + + if(dist > 0.0) + { + VECADDFAC(pos, light_start, data.ray.direction, dist); + } + return dist; + +} + diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3029e482312..8a376a0a170 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -94,6 +94,7 @@ #include "DNA_sdna_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_smoke_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" #include "DNA_texture_types.h" @@ -3539,6 +3540,17 @@ static void lib_link_object(FileData *fd, Main *main) if(fluidmd && fluidmd->fss) fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); } + + { + SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke); + + if(smd && smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) + { + smd->domain->coll_group = newlibadr_us(fd, ob->id.lib, smd->domain->coll_group); + smd->domain->eff_group = newlibadr_us(fd, ob->id.lib, smd->domain->eff_group); + smd->domain->fluid_group = newlibadr_us(fd, ob->id.lib, smd->domain->fluid_group); + } + } /* texture field */ if(ob->pd) @@ -3630,6 +3642,44 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) fluidmd->fss= newdataadr(fd, fluidmd->fss); fluidmd->fss->meshSurfNormals = 0; } + else if (md->type==eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData*) md; + + if(smd->type==MOD_SMOKE_TYPE_DOMAIN) + { + smd->flow = NULL; + smd->coll = NULL; + if(smd->domain) + smd->domain = newdataadr(fd, smd->domain); + + smd->domain->fluid = NULL; + smd->domain->tvox = NULL; + smd->domain->tray = NULL; + smd->domain->tvoxbig = NULL; + smd->domain->traybig = NULL; + smd->domain->bind = NULL; + smd->domain->max_textures = 0; + smd->domain->viewsettings = 0; // reset view for new frame + } + else if(smd->type==MOD_SMOKE_TYPE_FLOW) + { + smd->domain = NULL; + smd->coll = NULL; + smd->flow = newdataadr(fd, smd->flow); + smd->flow->psys = newdataadr(fd, smd->flow->psys); + } + else if(smd->type==MOD_SMOKE_TYPE_COLL) + { + smd->flow = NULL; + smd->domain = NULL; + smd->coll = NULL; + /* + smd->coll = newdataadr(fd, smd->coll); + smd->coll->points = NULL; + smd->coll->numpoints = 0; + */ + } + } else if (md->type==eModifierType_Collision) { CollisionModifierData *collmd = (CollisionModifierData*) md; @@ -4846,7 +4896,7 @@ static void direct_link_screen(FileData *fd, bScreen *sc) } else if(sl->spacetype==SPACE_LOGIC) { SpaceLogic *slogic= (SpaceLogic *)sl; - + if(slogic->gpd) { slogic->gpd= newdataadr(fd, slogic->gpd); direct_link_gpencil(fd, slogic->gpd); @@ -10130,6 +10180,19 @@ static void expand_modifier(FileData *fd, Main *mainvar, ModifierData *md) expand_doit(fd, mainvar, dmd->map_object); expand_doit(fd, mainvar, dmd->texture); } + else if (md->type==eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData*) md; + + if(smd->type==MOD_SMOKE_TYPE_DOMAIN && smd->domain) + { + //if(smd->domain->coll_group) + expand_doit(fd, mainvar, smd->domain->coll_group); + //if(smd->domain->fluid_group) + expand_doit(fd, mainvar, smd->domain->fluid_group); + //if(smd->domain->eff_group) + expand_doit(fd, mainvar, smd->domain->eff_group); + } + } } static void expand_object(FileData *fd, Main *mainvar, Object *ob) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 0f693b6de31..da68132700d 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -130,6 +130,7 @@ Any case: direct data is ALWAYS after the lib block #include "DNA_sdna_types.h" #include "DNA_sequence_types.h" #include "DNA_sensor_types.h" +#include "DNA_smoke_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_sound_types.h" @@ -1116,6 +1117,18 @@ static void write_modifiers(WriteData *wd, ListBase *modbase, int write_undo) writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms); write_pointcaches(wd, clmd->point_cache, PTCACHE_WRITE_CLOTH); } + else if(md->type==eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData*) md; + + if(smd->type==MOD_SMOKE_TYPE_DOMAIN) + writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain); + else if(smd->type==MOD_SMOKE_TYPE_FLOW) + writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow); + /* + else if(smd->type==MOD_SMOKE_TYPE_COLL) + writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll); + */ + } else if(md->type==eModifierType_Fluidsim) { FluidsimModifierData *fluidmd = (FluidsimModifierData*) md; diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index b7a868ad537..28cfcb3ff6e 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -35,7 +35,7 @@ SET(INC ../windowmanager ../../../intern/decimation/extern ../blenloader ../python ../../kernel/gen_system ../../../intern/SoundSystem ../readstreamglue ../quicktime ../../../intern/elbeem/extern - ../../../intern/ghost ../../../intern/opennl/extern ../../../extern/glew/include + ../../../intern/ghost ../../../intern/opennl/extern ../../../extern/glew/include ../../../intern/smoke/extern ../nodes ../gpu ../blenfont diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript index 7d51d237ef0..4eb9f3f5ecb 100644 --- a/source/blender/editors/space_view3d/SConscript +++ b/source/blender/editors/space_view3d/SConscript @@ -8,6 +8,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include #/intern/guardedalloc' incs += ' ../../gpu ../../makesrna ../../blenfont' +incs += ' #/intern/smoke/extern' if env['WITH_BF_GAMEENGINE']: defs.append('GAMEBLENDER=1') diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 53630b2bee0..d0bee9c18f8 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -59,6 +59,7 @@ #include "DNA_space_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_smoke_types.h" #include "DNA_userdef_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" @@ -88,7 +89,9 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_property.h" +#include "BKE_smoke.h" #include "BKE_utildefines.h" +#include "smoke_API.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -4898,6 +4901,7 @@ void drawRBpivot(bRigidBodyJointConstraint *data) void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) { static int warning_recursive= 0; + ModifierData *md = NULL; Object *ob; Curve *cu; RegionView3D *rv3d= ar->regiondata; @@ -5293,6 +5297,333 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) if(col) cpack(col); } + /* draw code for smoke */ + if(md = modifiers_findByType(ob, eModifierType_Smoke)) + { + SmokeModifierData *smd = (SmokeModifierData *)md; + + // draw collision objects + if((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) + { + SmokeCollSettings *scs = smd->coll; + /* + if(scs->points) + { + size_t i; + + wmLoadMatrix(rv3d->viewmat); + + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + + + // glPointSize(3.0); + bglBegin(GL_POINTS); + + for(i = 0; i < scs->numpoints; i++) + { + bglVertex3fv(&scs->points[3*i]); + } + + bglEnd(); + glPointSize(1.0); + + wmMultMatrix(ob->obmat); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + if(col) cpack(col); + + } + */ + } + + // only draw domains + if(smd->domain && smd->domain->fluid) + { + int x, y, z, i; + float *density = NULL; + float viewnormal[3]; + int mainaxis[3] = {0,0,0}; + float align = 0; + int max_textures = 0, counter_textures = 0; + int counter=0; + float *buffer = NULL; + int res[3]; + float bigfactor = 1.0; + int big = smd->domain->flags & MOD_SMOKE_HIGHRES; + int new = 0; + + // GUI sent redraw event + if(smd->domain->flags & MOD_SMOKE_VIEW_REDRAWNICE) + { + new = 1; + smd->domain->flags &= ~MOD_SMOKE_VIEW_REDRAWNICE; + } + + if(!big) + { + res[0] = smd->domain->res[0]; + res[1] = smd->domain->res[1]; + res[2] = smd->domain->res[2]; + } + else + { + smoke_get_bigres(smd->domain->fluid, res); + bigfactor = 1.0 / smd->domain->amplify; + } + + wmLoadMatrix(rv3d->viewmat); + + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + + // get view vector + VECCOPY(viewnormal, rv3d->viewinv[2]); + Normalize(viewnormal); + for(i = 0; i < 3; i++) + { + if(ABS(viewnormal[i]) > align) + { + mainaxis[0] = i; + align = ABS(viewnormal[i]); + } + } + mainaxis[1] = (mainaxis[0] + 1) % 3; + mainaxis[2] = (mainaxis[0] + 2) % 3; + + if(!smd->domain->bind) + { + smd->domain->bind = MEM_callocN(sizeof(GLuint)*256, "Smoke_bind"); + if(big) + smd->domain->viewsettings |= MOD_SMOKE_VIEW_CHANGETOBIG; + new = 3; + } + + // check if view axis / mode has been changed + if(smd->domain->viewsettings) + { + if(big) + { + if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_BIG)) + new = 2; + else if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_CHANGETOBIG)) + new = 1; + + smd->domain->viewsettings |= MOD_SMOKE_VIEW_CHANGETOBIG; + } + else + { + if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_SMALL)) + new = 2; + else if(smd->domain->viewsettings & MOD_SMOKE_VIEW_CHANGETOBIG) + new = 1; + + smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_CHANGETOBIG; + } + + if(!new) + { + if((mainaxis[0] == 0) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_X)) + new = 1; + else if((mainaxis[0] == 1) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_Y)) + new = 1; + else if((mainaxis[0] == 2) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_Z)) + new = 1; + + // printf("check axis\n"); + } + } + else + new = 3; + + if(new > 1) + { + float light[3] = {0.0,0.0,2.0}; + + if(!big && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SMALL)) + { + smoke_prepare_View(smd, light); + // printf("prepared View!\n"); + } + else if(big && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_BIG)) + { + smoke_prepare_bigView(smd, light); + // printf("prepared bigView!\n"); + } + } + + // printf("big: %d, new: %d\n", big, new); + + // only create buffer if we need to create new textures + if(new) + buffer = MEM_mallocN(sizeof(float)*res[mainaxis[1]]*res[mainaxis[2]]*4, "SmokeDrawBuffer"); + + if(buffer || smd->domain->viewsettings) + { + int mod_texture = 0; + + // printf("if(buffer || smd->domain->viewsettings)\n"); + + max_textures = (res[mainaxis[0]] > 256) ? 256 : res[mainaxis[0]]; + + if(!smd->domain->viewsettings) // new frame or new start + { + smd->domain->max_textures = max_textures; + glGenTextures(smd->domain->max_textures, smd->domain->bind); + new = 1; + // printf("glGenTextures\n"); + } + else + { + if(new) + { + // printf("glDeleteTextures\n"); + glDeleteTextures(smd->domain->max_textures, smd->domain->bind); + smd->domain->max_textures = max_textures; + glGenTextures(smd->domain->max_textures, smd->domain->bind); + } + } + + mod_texture = MAX3(1, smd->domain->visibility, (int)(res[mainaxis[0]] / smd->domain->max_textures )); + + for (z = res[mainaxis[0]]-1; z >= 0; z--) // 2 + { + float quad[4][3]; + + if(new) + { + for (y = 0; y < res[mainaxis[1]]; y++) // 1 + { + for (x = 0; x < res[mainaxis[2]]; x++) // 0 + { + size_t index; + size_t image_index; + float tray, tvox; + + if(mainaxis[0] == 0) + { + // mainaxis[1] == 1, mainaxis[2] == 2 + image_index = smoke_get_index2d(y, res[mainaxis[1]], x, res[mainaxis[2]], z, res[mainaxis[0]]); + index = smoke_get_index(z, res[mainaxis[0]], y, res[mainaxis[1]], x, res[mainaxis[2]]); + } + else if(mainaxis[0] == 1) + { + // mainaxis[1] == 2, mainaxis[2] == 0 + image_index = smoke_get_index2d(y, res[mainaxis[1]], x, res[mainaxis[2]], z, res[mainaxis[0]]); + index = smoke_get_index(x, res[mainaxis[2]], z, res[mainaxis[0]], y, res[mainaxis[1]]); + } + else // mainaxis[0] == 2 + { + // mainaxis[1] == 0, mainaxis[2] == 1 + image_index = smoke_get_index2d(y, res[mainaxis[1]], x, res[mainaxis[2]], z, res[mainaxis[0]]); + index = smoke_get_index(y, res[mainaxis[1]], x, res[mainaxis[2]], z, res[mainaxis[0]]); + } + + if(!big) + { + tvox = smoke_get_tvox(smd, index); + tray = smoke_get_tray(smd, index); + } + else + { + tvox = smoke_get_bigtvox(smd, index); + tray = smoke_get_bigtray(smd, index); + } + + // fill buffer with luminance and alpha + // 1 - T_vox + buffer[image_index*4 + 3] = 1.0 - tvox; // 0 = transparent => d.h. tvox = 1 + + // L_vox = Omega * L_light * (1 - T_vox) * T_ray + buffer[image_index*4] = buffer[image_index*4 + 1] = buffer[image_index*4 + 2] = smd->domain->omega * 1.0 * tvox * tray; + } + } + } + glBindTexture(GL_TEXTURE_2D, smd->domain->bind[counter_textures]); + glEnable(GL_TEXTURE_2D); + + if(new) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res[mainaxis[1]], res[mainaxis[2]], 0, GL_RGBA, GL_FLOAT, buffer); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering + } + + if((z % mod_texture) == 0 ) + { + // botttom left + quad[3][mainaxis[0]] = smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[3][mainaxis[1]] = smd->domain->p0[mainaxis[1]] + smd->domain->dx * bigfactor * 0.5; + quad[3][mainaxis[2]] = smd->domain->p0[mainaxis[2]] + smd->domain->dx * bigfactor * 0.5; + + // top right + quad[1][mainaxis[0]] = smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[1][mainaxis[1]] = smd->domain->p0[mainaxis[1]] + (res[mainaxis[1]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[1][mainaxis[2]] = smd->domain->p0[mainaxis[2]] + (res[mainaxis[2]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + + // top left + quad[2][mainaxis[0]] = smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[2][mainaxis[1]] = smd->domain->p0[mainaxis[1]] + smd->domain->dx * bigfactor * 0.5; + quad[2][mainaxis[2]] = smd->domain->p0[mainaxis[2]] + (res[mainaxis[2]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + + // bottom right + quad[0][mainaxis[0]] = smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[0][mainaxis[1]] = smd->domain->p0[mainaxis[1]] + (res[mainaxis[1]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5; + quad[0][mainaxis[2]] = smd->domain->p0[mainaxis[2]] + smd->domain->dx * bigfactor * 0.5; + + glBegin(GL_QUADS); // Start Drawing Quads + + glTexCoord2f(1.0f, 0.0f); + glVertex3fv(quad[0]); // Left And Up 1 Unit (Top Left) + glTexCoord2f(1.0f, 1.0f); + glVertex3fv(quad[1]); // Right And Up 1 Unit (Top Right) + glTexCoord2f(0.0f, 1.0f); + glVertex3fv(quad[2]); // Right And Down One Unit (Bottom Right) + glTexCoord2f(0.0f, 0.0f); + glVertex3fv(quad[3]); // Left And Down One Unit (Bottom Left) + + glEnd(); + } + counter_textures++; + } + } + if(buffer) + { + MEM_freeN(buffer); + buffer = NULL; + } + + // set correct flag for viewsettings + if(1) + { + // do not clear BIG/SMALL flag + smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_X; + smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_Y; + smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_Z; + + // set what caches we have + if(big) + smd->domain->viewsettings |= MOD_SMOKE_VIEW_BIG; + else + smd->domain->viewsettings |= MOD_SMOKE_VIEW_SMALL; + + if(mainaxis[0] == 0) + smd->domain->viewsettings |= MOD_SMOKE_VIEW_X; + else if(mainaxis[0] == 1) + smd->domain->viewsettings |= MOD_SMOKE_VIEW_Y; + else if(mainaxis[0] == 2) + smd->domain->viewsettings |= MOD_SMOKE_VIEW_Z; + } + + wmMultMatrix(ob->obmat); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + if(col) cpack(col); + } + } + { bConstraint *con; for(con=ob->constraints.first; con; con= con->next) diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index ab053c136ea..3f504848d77 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -41,6 +41,7 @@ typedef enum ModifierType { eModifierType_SimpleDeform, eModifierType_Multires, eModifierType_Surface, + eModifierType_Smoke, NUM_MODIFIER_TYPES } ModifierType; @@ -237,6 +238,23 @@ typedef struct BMeshModifierData { int type; } BMeshModifierData; + +/* Smoke modifier flags */ +#define MOD_SMOKE_TYPE_DOMAIN (1 << 0) +#define MOD_SMOKE_TYPE_FLOW (1 << 1) +#define MOD_SMOKE_TYPE_COLL (1 << 2) + +typedef struct SmokeModifierData { + ModifierData modifier; + + struct SmokeDomainSettings *domain; + struct SmokeFlowSettings *flow; /* inflow, outflow, smoke objects */ + struct SmokeCollSettings *coll; /* collision objects */ + float time; + int type; /* domain, inflow, outflow, ... */ + struct PointCache *point_cache; /* definition is in DNA_object_force.h */ +} SmokeModifierData; + typedef struct DisplaceModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h new file mode 100644 index 00000000000..aac75309be2 --- /dev/null +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -0,0 +1,112 @@ +/** +* $Id: DNA_cloth_types.h 19820 2009-04-20 15:06:46Z blendix $ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Daniel Genrich (Genscher) +* +* ***** END GPL LICENSE BLOCK ***** +*/ +#ifndef DNA_SMOKE_TYPES_H +#define DNA_SMOKE_TYPES_H + +/* flags */ +#define MOD_SMOKE_HIGHRES (1<<1) +/* noise */ +#define MOD_SMOKE_NOISEWAVE (1<<0) +#define MOD_SMOKE_NOISEFFT (1<<1) +#define MOD_SMOKE_NOISECURL (1<<2) +/* viewsettings */ +#define MOD_SMOKE_VIEW_X (1<<0) +#define MOD_SMOKE_VIEW_Y (1<<1) +#define MOD_SMOKE_VIEW_Z (1<<2) +#define MOD_SMOKE_VIEW_SMALL (1<<3) +#define MOD_SMOKE_VIEW_BIG (1<<4) +#define MOD_SMOKE_VIEW_CHANGETOBIG (1<<5) +#define MOD_SMOKE_VIEW_REDRAWNICE (1<<6) +#define MOD_SMOKE_VIEW_REDRAWALL (1<<7) + +typedef struct SmokeDomainSettings { + struct SmokeModifierData *smd; /* for fast RNA access */ + struct FLUID_3D *fluid; + struct Group *fluid_group; + struct Group *eff_group; // effector group for e.g. wind force + struct Group *coll_group; // collision objects group + unsigned int *bind; + float *tvox; + float *tray; + float *tvoxbig; + float *traybig; + float p0[3]; /* start point of BB */ + float p1[3]; /* end point of BB */ + float dx; /* edge length of one cell */ + float firstframe; + float lastframe; + float omega; /* smoke color - from 0 to 1 */ + float temp; /* fluid temperature */ + float tempAmb; /* ambient temperature */ + float alpha; + float beta; + int res[3]; /* domain resolution */ + int amplify; /* wavelet amplification */ + int maxres; /* longest axis on the BB gets this resolution assigned */ + int flags; /* show up-res or low res, etc */ + int visibility; /* how many billboards to show (every 2nd, 3rd, 4th,..) */ + int viewsettings; + int max_textures; + short noise; /* noise type: wave, curl, anisotropic */ + short pad2; + int pad3; + int pad4; +} SmokeDomainSettings; + +/* inflow / outflow */ +typedef struct SmokeFlowSettings { + struct SmokeModifierData *smd; /* for fast RNA access */ + struct ParticleSystem *psys; + float density; + float temp; /* delta temperature (temp - ambient temp) */ + float velocity[3]; + float vgrp_heat_scale[2]; /* min and max scaling for vgroup_heat */ + short vgroup_flow; /* where inflow/outflow happens - red=1=action */ + short vgroup_density; + short vgroup_heat; + short type; /* inflow =0 or outflow = 1 */ + int pad; +} SmokeFlowSettings; + +/* collision objects (filled with smoke) */ +typedef struct SmokeCollSettings { + struct SmokeModifierData *smd; /* for fast RNA access */ + float *points; + float *points_old; + float *vel; + float mat[4][4]; + float mat_old[4][4]; + int numpoints; + int numverts; // check if mesh changed + short type; // static = 0, rigid = 1, dynamic = 2 + short pad; + int pad2; +} SmokeCollSettings; + +#endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 207d6fdd94a..87ceef36dfb 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -132,6 +132,7 @@ char *includefiles[] = { "DNA_windowmanager_types.h", "DNA_anim_types.h", "DNA_boid_types.h", + "DNA_smoke_types.h", // empty string to indicate end of includefiles "" @@ -1154,4 +1155,5 @@ int main(int argc, char ** argv) #include "DNA_windowmanager_types.h" #include "DNA_anim_types.h" #include "DNA_boid_types.h" +#include "DNA_smoke_types.h" /* end of list */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 64a4887701b..1b3175d7f55 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -378,6 +378,7 @@ extern StructRNA RNA_ShapeKeyPoint; extern StructRNA RNA_ShrinkwrapConstraint; extern StructRNA RNA_ShrinkwrapModifier; extern StructRNA RNA_SimpleDeformModifier; +extern StructRNA RNA_SmokeModifier; extern StructRNA RNA_SmoothModifier; extern StructRNA RNA_SoftBodyModifier; extern StructRNA RNA_SoftBodySettings; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 0b7fa0e4634..b5fc4d2e463 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1941,6 +1941,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint}, {"rna_sensor.c", NULL, RNA_def_sensor}, {"rna_sequence.c", NULL, RNA_def_sequence}, + {"rna_smoke.c", NULL, RNA_def_smoke}, {"rna_space.c", NULL, RNA_def_space}, {"rna_text.c", NULL, RNA_def_text}, {"rna_timeline.c", NULL, RNA_def_timeline_marker}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index ed0395ede23..99f527f8875 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -154,6 +154,7 @@ void RNA_def_screen(struct BlenderRNA *brna); void RNA_def_sculpt_paint(struct BlenderRNA *brna); void RNA_def_sensor(struct BlenderRNA *brna); void RNA_def_sequence(struct BlenderRNA *brna); +void RNA_def_smoke(struct BlenderRNA *brna); void RNA_def_space(struct BlenderRNA *brna); void RNA_def_text(struct BlenderRNA *brna); void RNA_def_texture(struct BlenderRNA *brna); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index c89cc4ad63e..022ef56b53b 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -71,6 +71,7 @@ EnumPropertyItem modifier_type_items[] ={ {eModifierType_Surface, "SURFACE", ICON_MOD_PHYSICS, "Surface", ""}, {eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""}, {eModifierType_Wave, "WAVE", ICON_MOD_WAVE, "Wave", ""}, + {eModifierType_Smoke, "SMOKE", 0, "Smoke", ""}, {0, NULL, 0, NULL, NULL}}; @@ -151,6 +152,8 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_MultiresModifier; case eModifierType_Surface: return &RNA_SurfaceModifier; + case eModifierType_Smoke: + return &RNA_SmokeModifier; default: return &RNA_Modifier; } @@ -172,6 +175,19 @@ static void rna_Modifier_dependency_update(bContext *C, PointerRNA *ptr) DAG_scene_sort(CTX_data_scene(C)); } +static void rna_Smoke_set_type(bContext *C, PointerRNA *ptr) +{ + SmokeModifierData *smd= (SmokeModifierData *)ptr->data; + + smokeModifier_free(smd); // XXX TODO: completely free all 3 pointers + smokeModifier_createType(smd); // create regarding of selected type + // particle_system_slot_add_exec(C, NULL); + // particle_system_slot_remove_exec(C, NULL); + + // update dependancy since a domain - other type switch could have happened + rna_Modifier_dependency_update(C, ptr); +} + static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value) { ExplodeModifierData *emd= (ExplodeModifierData*)ptr->data; @@ -1466,6 +1482,41 @@ static void rna_def_modifier_cloth(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Point Cache", ""); } +static void rna_def_modifier_smoke(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_smoke_type_items[] = { + {0, "NONE", 0, "None", ""}, + {MOD_SMOKE_TYPE_DOMAIN, "TYPE_DOMAIN", 0, "Domain", ""}, + {MOD_SMOKE_TYPE_FLOW, "TYPE_FLOW", 0, "Flow", "Inflow/Outflow"}, + {MOD_SMOKE_TYPE_COLL, "TYPE_COLL", 0, "Collision", ""}, + {0, NULL, 0, NULL, NULL}}; + + srna= RNA_def_struct(brna, "SmokeModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Smoke Modifier", "Smoke simulation modifier."); + RNA_def_struct_sdna(srna, "SmokeModifierData"); + + prop= RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "domain"); + RNA_def_property_ui_text(prop, "Domain Settings", ""); + + prop= RNA_def_property(srna, "flow_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "flow"); + RNA_def_property_ui_text(prop, "Flow Settings", ""); + + prop= RNA_def_property(srna, "coll_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "coll"); + RNA_def_property_ui_text(prop, "Collision Settings", ""); + + prop= RNA_def_property(srna, "fluid_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, prop_smoke_type_items); + RNA_def_property_ui_text(prop, "Type", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_set_type"); +} + static void rna_def_modifier_collision(BlenderRNA *brna) { StructRNA *srna; @@ -1763,7 +1814,6 @@ static void rna_def_modifier_surface(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SurfaceModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_PHYSICS); } - void RNA_def_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -1847,6 +1897,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_simpledeform(brna); rna_def_modifier_multires(brna); rna_def_modifier_surface(brna); + rna_def_modifier_smoke(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c new file mode 100644 index 00000000000..a4e2c39ecd8 --- /dev/null +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -0,0 +1,263 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Daniel Genrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <limits.h> + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "rna_internal.h" + +#include "BKE_modifier.h" +#include "BKE_smoke.h" + +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_smoke_types.h" + +#include "WM_types.h" + + +#ifdef RNA_RUNTIME + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_particle.h" + +#include "ED_object.h" + +static void rna_Smoke_update(bContext *C, PointerRNA *ptr) +{ + DAG_object_flush_update(CTX_data_scene(C), ptr->id.data, OB_RECALC_DATA); +} + +static void rna_Smoke_dependency_update(bContext *C, PointerRNA *ptr) +{ + rna_Smoke_update(C, ptr); + DAG_scene_sort(CTX_data_scene(C)); +} + +static void rna_Smoke_reset(bContext *C, PointerRNA *ptr) +{ + SmokeDomainSettings *settings = (SmokeDomainSettings*)ptr->data; + + smokeModifier_reset(settings->smd); + + rna_Smoke_update(C, ptr); +} + +static void rna_Smoke_reset_dependancy(bContext *C, PointerRNA *ptr) +{ + SmokeDomainSettings *settings = (SmokeDomainSettings*)ptr->data; + + smokeModifier_reset(settings->smd); + + rna_Smoke_dependency_update(C, ptr); +} + +static void rna_Smoke_redraw(bContext *C, PointerRNA *ptr) +{ + SmokeDomainSettings *settings = (SmokeDomainSettings*)ptr->data; + + settings->flags |= MOD_SMOKE_VIEW_REDRAWNICE; +} + +static char *rna_SmokeDomainSettings_path(PointerRNA *ptr) +{ + SmokeDomainSettings *settings = (SmokeDomainSettings*)ptr->data; + ModifierData *md= (ModifierData *)settings->smd; + + return BLI_sprintfN("modifiers[%s].domain_settings", md->name); +} + +static char *rna_SmokeFlowSettings_path(PointerRNA *ptr) +{ + SmokeFlowSettings *settings = (SmokeFlowSettings*)ptr->data; + ModifierData *md= (ModifierData *)settings->smd; + + return BLI_sprintfN("modifiers[%s].flow_settings", md->name); +} + +static char *rna_SmokeCollSettings_path(PointerRNA *ptr) +{ + SmokeCollSettings *settings = (SmokeCollSettings*)ptr->data; + ModifierData *md= (ModifierData *)settings->smd; + + return BLI_sprintfN("modifiers[%s].coll_settings", md->name); +} + +#else + +static void rna_def_smoke_domain_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_noise_type_items[] = { + {MOD_SMOKE_NOISEWAVE, "NOISEWAVE", 0, "Wavelet", ""}, + {MOD_SMOKE_NOISEFFT, "NOISEFFT", 0, "FFT", ""}, + {MOD_SMOKE_NOISECURL, "NOISECURL", 0, "Curl", ""}, + {0, NULL, 0, NULL, NULL}}; + + srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); + RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings."); + RNA_def_struct_sdna(srna, "SmokeDomainSettings"); + RNA_def_struct_path_func(srna, "rna_SmokeDomainSettings_path"); + + prop= RNA_def_property(srna, "maxres", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "maxres"); + RNA_def_property_range(prop, 32, 512); + RNA_def_property_ui_range(prop, 32, 512, 2, 0); + RNA_def_property_ui_text(prop, "Max Res", "Maximal resolution used in the fluid domain."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + + prop= RNA_def_property(srna, "color", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "omega"); + RNA_def_property_range(prop, 0.02, 1.0); + RNA_def_property_ui_range(prop, 0.02, 1.0, 0.02, 2); + RNA_def_property_ui_text(prop, "Color", "Smoke color (0 = black, 1 = white)."); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Smoke_redraw"); + + prop= RNA_def_property(srna, "amplify", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "amplify"); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_range(prop, 1, 10, 1, 0); + RNA_def_property_ui_text(prop, "Amplification", "Enhance the resolution of smoke by this factor using noise."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + + prop= RNA_def_property(srna, "highres", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES); + RNA_def_property_ui_text(prop, "High res", "Show high resolution (using amplification)."); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); + + prop= RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "noise"); + RNA_def_property_enum_items(prop, prop_noise_type_items); + RNA_def_property_ui_text(prop, "Noise Method", "Noise method which is used for creating the high resolution"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + + prop= RNA_def_property(srna, "visibility", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "visibility"); + RNA_def_property_range(prop, 1, 15); + RNA_def_property_ui_range(prop, 1, 15, 1, 0); + RNA_def_property_ui_text(prop, "Display", "How much of the resolution should be shown during preview (every 2nd, 3rd, etc)."); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Smoke_redraw"); + + prop= RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "alpha"); + RNA_def_property_range(prop, -5.0, 5.0); + RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); + RNA_def_property_ui_text(prop, "Gravity", "Higher value results in sinking smoke"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL); + + prop= RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "beta"); + RNA_def_property_range(prop, -5.0, 5.0); + RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); + RNA_def_property_ui_text(prop, "Heat", "Higher value results in faster rising smoke."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL); + + prop= RNA_def_property(srna, "coll_group", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "coll_group"); + RNA_def_property_struct_type(prop, "Group"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Collision Group", "Limit collisions to this group."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset_dependancy"); + + prop= RNA_def_property(srna, "fluid_group", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "fluid_group"); + RNA_def_property_struct_type(prop, "Group"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Fluid Group", "Limit fluid objects to this group."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset_dependancy"); + + prop= RNA_def_property(srna, "eff_group", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "eff_group"); + RNA_def_property_struct_type(prop, "Group"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Effector Group", "Limit effectors to this group."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset_dependancy"); +} + +static void rna_def_smoke_flow_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL); + RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings."); + RNA_def_struct_sdna(srna, "SmokeFlowSettings"); + RNA_def_struct_path_func(srna, "rna_SmokeFlowSettings_path"); + + prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "density"); + RNA_def_property_range(prop, 0.001, 1); + RNA_def_property_ui_range(prop, 0.001, 1.0, 1.0, 4); + RNA_def_property_ui_text(prop, "Density", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL); + + prop= RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "temp"); + RNA_def_property_range(prop, -10, 10); + RNA_def_property_ui_range(prop, -10, 10, 1, 1); + RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambientt temperature."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL); + + prop= RNA_def_property(srna, "psys", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "psys"); + RNA_def_property_struct_type(prop, "ParticleSystem"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset_dependancy"); + + prop= RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VECTOR); + RNA_def_property_float_sdna(prop, NULL, "velocity"); + RNA_def_property_range(prop, -10, 10); + RNA_def_property_ui_range(prop, -10, 10, 1, 1); + RNA_def_property_ui_text(prop, "Velocity", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL); + +} + +static void rna_def_smoke_coll_settings(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "SmokeCollSettings", NULL); + RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings."); + RNA_def_struct_sdna(srna, "SmokeCollSettings"); + RNA_def_struct_path_func(srna, "rna_SmokeCollSettings_path"); +} + +void RNA_def_smoke(BlenderRNA *brna) +{ + rna_def_smoke_domain_settings(brna); + rna_def_smoke_flow_settings(brna); + rna_def_smoke_coll_settings(brna); +} + +#endif + diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 70a25d8662f..064681b37ea 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -256,6 +256,7 @@ IF(UNIX) bf_converter bf_dummy bf_bullet + bf_smoke bf_common bf_ketsji bf_logic |