Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_object.h8
-rw-r--r--source/blender/blenkernel/intern/material.c2
-rw-r--r--source/blender/blenkernel/intern/object.c155
-rw-r--r--source/blender/blenloader/intern/readfile.c19
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/object_intern.h4
-rw-r--r--source/blender/editors/object/object_lod.c102
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c2
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c25
-rw-r--r--source/blender/gpu/intern/gpu_draw.c2
-rw-r--r--source/blender/makesdna/DNA_object_types.h16
-rw-r--r--source/blender/makesrna/intern/rna_object.c49
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp30
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp39
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h18
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp13
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h3
23 files changed, 497 insertions, 5 deletions
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index e99eb2a64f2..44a4b640121 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -84,6 +84,14 @@ struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const ch
struct Object *BKE_object_add(struct Main *bmain, struct Scene *scene, int type);
void *BKE_object_obdata_add_from_type(struct Main *bmain, int type);
+void BKE_object_lod_add(struct Object *ob);
+void BKE_object_lod_sort(struct Object *ob);
+bool BKE_object_lod_remove(struct Object *ob, int level);
+bool BKE_object_lod_update(struct Object *ob, float camera_position[3]);
+bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene);
+struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene);
+struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
+
struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, int copy_caches);
struct Object *BKE_object_copy(struct Object *ob);
void BKE_object_make_local(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index f3dc64a7279..2752e41ea2d 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -675,7 +675,7 @@ Material *give_current_material(Object *ob, short act)
{
Material ***matarar, *ma;
short *totcolp;
-
+
if (ob == NULL) return NULL;
/* if object cannot have material, (totcolp == NULL) */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 8c2475369de..2b95b2346f6 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -356,6 +356,8 @@ void BKE_object_free(Object *ob)
if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
+ BLI_freelistN(&ob->lodlevels);
+
/* Free runtime curves data. */
if (ob->curve_cache) {
BLI_freelistN(&ob->curve_cache->bev);
@@ -395,6 +397,7 @@ void BKE_object_unlink(Object *ob)
ModifierData *md;
ARegion *ar;
RegionView3D *rv3d;
+ LodLevel *lod;
int a, found;
unlink_controllers(&ob->controllers);
@@ -573,6 +576,12 @@ void BKE_object_unlink(Object *ob)
DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
}
+ /* levels of detail */
+ for (lod = obt->lodlevels.first; lod; lod = lod->next) {
+ if (lod->source == ob)
+ lod->source = NULL;
+ }
+
obt = obt->id.next;
}
@@ -876,6 +885,7 @@ static const char *get_obdata_defname(int type)
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
Object *ob;
+ LodLevel *base;
if (!name)
name = get_obdata_defname(type);
@@ -980,6 +990,138 @@ Object *BKE_object_add(Main *bmain, Scene *scene, int type)
return ob;
}
+void BKE_object_lod_add(Object *ob)
+{
+ LodLevel *lod = MEM_callocN(sizeof(LodLevel), "LoD Level");
+ LodLevel *last = ob->lodlevels.last;
+
+ /* If the lod list is empty, initialize it with the base lod level */
+ if (!last) {
+ LodLevel *base = MEM_callocN(sizeof(LodLevel), "Base LoD Level");
+ BLI_addtail(&ob->lodlevels, base);
+ base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
+ base->source = ob;
+ last = ob->currentlod = base;
+ }
+
+ lod->distance = last->distance + 25.0f;
+ lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
+
+ BLI_addtail(&ob->lodlevels, lod);
+}
+
+static int lod_cmp(void *a, void *b)
+{
+ LodLevel *loda = (LodLevel*)a;
+ LodLevel *lodb = (LodLevel*)b;
+
+ if (loda->distance < lodb->distance) return -1;
+ return loda->distance > lodb->distance;
+}
+
+void BKE_object_lod_sort(Object *ob)
+{
+ BLI_sortlist(&ob->lodlevels, lod_cmp);
+}
+
+bool BKE_object_lod_remove(Object *ob, int level)
+{
+ LodLevel *rem;
+
+ if (level < 1 || level > BLI_countlist(&ob->lodlevels) - 1)
+ return false;
+
+ rem = BLI_findlink(&ob->lodlevels, level);
+
+ if (rem == ob->currentlod) {
+ ob->currentlod = rem->prev;
+ }
+
+ BLI_remlink(&ob->lodlevels, rem);
+ MEM_freeN(rem);
+
+ /* If there are no user defined lods, remove the base lod as well */
+ if (BLI_countlist(&ob->lodlevels) == 1) {
+ LodLevel *base = ob->lodlevels.first;
+ BLI_remlink(&ob->lodlevels, base);
+ MEM_freeN(base);
+ ob->currentlod = NULL;
+ }
+
+ return true;
+}
+
+static LodLevel* lod_level_select(Object *ob, float cam_loc[3])
+{
+ LodLevel *current = ob->currentlod;
+ float ob_loc[3], delta[3];
+ float distance2;
+
+ if (!current) return NULL;
+
+ copy_v3_v3(ob_loc, ob->obmat[3]);
+ sub_v3_v3v3(delta, ob_loc, cam_loc);
+ distance2 = len_squared_v3(delta);
+
+ /* check for higher LoD */
+ if (distance2 < current->distance*current->distance) {
+ while (current->prev && distance2 < current->distance*current->distance) {
+ current = current->prev;
+ }
+ }
+ /* check for lower LoD */
+ else {
+ while (current->next && distance2 > current->next->distance*current->next->distance) {
+ current = current->next;
+ }
+ }
+
+ return current;
+}
+
+bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
+{
+ bool active = (scene) ? ob == OBACT : 0;
+ return (ob->mode == OB_MODE_OBJECT || !active);
+}
+
+bool BKE_object_lod_update(Object *ob, float camera_position[3])
+{
+ LodLevel* cur_level = ob->currentlod;
+ LodLevel* new_level = lod_level_select(ob, camera_position);
+
+ if (new_level != cur_level) {
+ ob->currentlod = new_level;
+ return true;
+ }
+
+ return false;
+}
+
+static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
+{
+ LodLevel *current = ob->currentlod;
+
+ if (!current || !BKE_object_lod_is_usable(ob, scene))
+ return ob;
+
+ while( current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
+ current = current->prev;
+ }
+
+ return current->source;
+}
+
+struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
+{
+ return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
+}
+
+struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
+{
+ return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+}
+
SoftBody *copy_softbody(SoftBody *sb, int copy_caches)
{
SoftBody *sbn;
@@ -1191,6 +1333,16 @@ static void copy_object_pose(Object *obn, Object *ob)
}
}
+static void copy_object_lod(Object *obn, Object *ob)
+{
+ BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels);
+
+ if (obn->lodlevels.first)
+ ((LodLevel*)obn->lodlevels.first)->source = obn;
+
+ obn->currentlod = (LodLevel*) obn->lodlevels.first;
+}
+
bool BKE_object_pose_context_check(Object *ob)
{
if ((ob) &&
@@ -1306,6 +1458,9 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, int copy_caches)
obn->mpath = NULL;
+ copy_object_lod(obn, ob);
+
+
/* Copy runtime surve data. */
obn->curve_cache = NULL;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 077b476c408..a9e9a07a2b1 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4520,6 +4520,16 @@ static void lib_link_object(FileData *fd, Main *main)
ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1);
ob->rigidbody_constraint->ob2 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob2);
}
+
+ {
+ LodLevel *level;
+ for (level = ob->lodlevels.first; level; level = level->next) {
+ level->source = newlibadr(fd, ob->id.lib, level->source);
+
+ if (!level->source && level == ob->lodlevels.first)
+ level->source = ob;
+ }
+ }
}
}
@@ -5045,6 +5055,9 @@ static void direct_link_object(FileData *fd, Object *ob)
if (ob->sculpt) {
ob->sculpt = MEM_callocN(sizeof(SculptSession), "reload sculpt session");
}
+
+ link_list(fd, &ob->lodlevels);
+ ob->currentlod = ob->lodlevels.first;
}
/* ************ READ SCENE ***************** */
@@ -10705,6 +10718,12 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
expand_doit(fd, mainvar, ob->rigidbody_constraint->ob2);
}
+ if (ob->currentlod) {
+ LodLevel *level;
+ for (level = ob->lodlevels.first; level; level = level->next) {
+ expand_doit(fd, mainvar, level->source);
+ }
+ }
}
static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index a2c91969cf8..cff5d796473 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1532,6 +1532,8 @@ static void write_objects(WriteData *wd, ListBase *idbase)
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
+
+ writelist(wd, DATA, "LodLevel", &ob->lodlevels);
}
ob= ob->id.next;
}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 3e7aeba63c3..e0440504b4a 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
object_group.c
object_hook.c
object_lattice.c
+ object_lod.c
object_modifier.c
object_ops.c
object_relations.c
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 4ff3bc9ac06..396ab73bb2c 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -249,5 +249,9 @@ void OBJECT_OT_group_remove(struct wmOperatorType *ot);
/* object_bake.c */
void OBJECT_OT_bake_image(wmOperatorType *ot);
+/* object_lod.c */
+void OBJECT_OT_lod_add(struct wmOperatorType *ot);
+void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
+
#endif /* __OBJECT_INTERN_H__ */
diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c
new file mode 100644
index 00000000000..952451ee21d
--- /dev/null
+++ b/source/blender/editors/object/object_lod.c
@@ -0,0 +1,102 @@
+/*
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_lod.c
+ * \ingroup edobj
+ */
+
+
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+
+#include "ED_screen.h"
+#include "ED_object.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "object_intern.h"
+
+static int object_lod_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ BKE_object_lod_add(ob);
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_lod_add(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Level of Detail";
+ ot->description = "Add a level of detail to this object";
+ ot->idname = "OBJECT_OT_lod_add";
+
+ /* api callbacks */
+ ot->exec = object_lod_add_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int object_lod_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ int index = RNA_int_get(op->ptr, "index");
+ if(!BKE_object_lod_remove(ob, index))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_LOD, CTX_wm_view3d(C));
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_lod_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Level of Detail";
+ ot->description = "Remove a level of detail from this object";
+ ot->idname = "OBJECT_OT_lod_remove";
+
+ /* api callbacks */
+ ot->exec = object_lod_remove_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_int(ot->srna, "index", 1, 1, INT_MAX, "Index", "", 1, INT_MAX);
+} \ No newline at end of file
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 333e5ff3006..66e27c212db 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -238,6 +238,9 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_bake_image);
WM_operatortype_append(OBJECT_OT_drop_named_material);
+
+ WM_operatortype_append(OBJECT_OT_lod_add);
+ WM_operatortype_append(OBJECT_OT_lod_remove);
}
void ED_operatormacros_object(void)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 3e27346f9fe..612e0fde194 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -3358,7 +3358,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
- Object *ob = base->object;
+ Object *ob = BKE_object_lod_meshob_get(base->object, scene);
Mesh *me = ob->data;
Material *ma = give_current_material(ob, 1);
const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 58c0df6b6bd..9f3da9250cc 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -788,6 +788,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
case ND_CONSTRAINT:
case ND_KEYS:
case ND_PARTICLE:
+ case ND_LOD:
ED_region_tag_redraw(ar);
break;
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 24edfb413c8..215d2b387d7 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2003,6 +2003,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
{
RegionView3D *rv3d = ar->regiondata;
ListBase *lb;
+ LodLevel *savedlod;
DupliObject *dob_prev = NULL, *dob, *dob_next = NULL;
Base tbase = {NULL};
BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
@@ -2023,6 +2024,13 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
tbase.object = dob->ob;
+ /* Make sure lod is updated from dupli's position */
+
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+ savedlod = dob->ob->currentlod;
+ BKE_object_lod_update(dob->ob, rv3d->viewinv[3]);
+
+
/* extra service: draw the duplicator in drawtype of parent, minimum taken
* to allow e.g. boundbox box objects in groups for LOD */
dt = tbase.object->dt;
@@ -2093,13 +2101,13 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
glLoadMatrixf(rv3d->viewmat);
}
else {
- copy_m4_m4(dob->ob->obmat, dob->mat);
draw_object(scene, ar, v3d, &tbase, DRAW_CONSTCOLOR);
}
tbase.object->dt = dt;
tbase.object->dtx = dtx;
tbase.object->transflag = transflag;
+ tbase.object->currentlod = savedlod;
}
/* Transp afterdraw disabled, afterdraw only stores base pointers, and duplis can be same obj */
@@ -3225,6 +3233,18 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
}
}
+static void update_lods(Scene *scene, float camera_pos[3])
+{
+ Scene *sce_iter;
+ Base *base;
+ Object *ob;
+
+ for (SETLOOPER(scene, sce_iter, base)) {
+ ob = base->object;
+ BKE_object_lod_update(ob, camera_pos);
+ }
+}
+
/* warning: this function has duplicate drawing in ED_view3d_draw_offscreen() */
static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const char **grid_unit)
{
@@ -3247,6 +3267,9 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const
/* setup view matrices */
view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ /* Make sure LoDs are up to date */
+ update_lods(scene, rv3d->viewinv[3]);
+
/* clear the background */
view3d_main_area_clear(scene, v3d, ar);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 0d25d988df9..365e18b6b78 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -1388,6 +1388,8 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
int gamma = BKE_scene_check_color_management_enabled(scene);
int new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
int use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP); /* assumes v3d->defmaterial->preview is set */
+
+ ob = BKE_object_lod_matob_get(ob, scene);
/* initialize state */
memset(&GMS, 0, sizeof(GMS));
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 2ff697f513f..f8a163ab8f8 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -105,6 +105,13 @@ enum {
BOUNDBOX_DIRTY = (1 << 1),
};
+typedef struct LodLevel {
+ struct LodLevel *next, *prev;
+ struct Object *source;
+ int flags;
+ float distance;
+} LodLevel;
+
typedef struct Object {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -279,6 +286,9 @@ typedef struct Object {
float ima_ofs[2]; /* offset for image empties */
+ ListBase lodlevels; /* contains data for levels of detail */
+ LodLevel *currentlod;
+
/* Runtime valuated curve-specific data, not stored in the file */
struct CurveCache *curve_cache;
} Object;
@@ -470,6 +480,12 @@ enum {
OB_BOUND_CAPSULE = 7,
};
+/* lod flags */
+enum {
+ OB_LOD_USE_MESH = 1 << 0,
+ OB_LOD_USE_MAT = 1 << 1,
+};
+
/* **************** BASE ********************* */
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 3f366dfbcfa..11a818c6a9c 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -40,6 +40,7 @@
#include "DNA_meta_types.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
@@ -1458,6 +1459,11 @@ int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
return (ss && ss->bm);
}
+static void rna_Object_lod_distance_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ BKE_object_lod_sort(ob);
+}
#else
static void rna_def_vertex_group(BlenderRNA *brna)
@@ -2013,6 +2019,41 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
}
+static void rna_def_object_lodlevel(BlenderRNA* brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LodLevel", NULL);
+ RNA_def_struct_sdna(srna, "LodLevel");
+
+ prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "distance");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Distance", "Distance to begin using this level of detail");
+ RNA_def_property_update(prop, NC_OBJECT|ND_LOD, "rna_Object_lod_distance_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "source");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object to use for this level of detail");
+ RNA_def_property_update(prop, NC_OBJECT|ND_LOD, NULL);
+
+ prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_MESH);
+ RNA_def_property_ui_text(prop, "Use Mesh", "Use the mesh from this object at this level of detail");
+ RNA_def_property_ui_icon(prop, ICON_MESH_DATA, 0);
+ RNA_def_property_update(prop, NC_OBJECT|ND_LOD, NULL);
+
+ prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_MAT);
+ RNA_def_property_ui_text(prop, "Use Material", "Use the material from this object at this level of detail");
+ RNA_def_property_ui_icon(prop, ICON_MATERIAL, 0);
+ RNA_def_property_update(prop, NC_OBJECT|ND_LOD, NULL);
+}
+
+
static void rna_def_object(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2673,6 +2714,13 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dynamic Topology Sculpting", NULL);
+ /* Levels of Detail */
+ prop = RNA_def_property(srna, "lod_levels", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "lodlevels", NULL);
+ RNA_def_property_struct_type(prop, "LodLevel");
+ RNA_def_property_ui_text(prop, "Level of Detail Levels", "A collection of detail levels to automatically switch between");
+ RNA_def_property_update(prop, NC_OBJECT|ND_LOD, NULL);
+
RNA_api_object(srna);
}
@@ -2783,6 +2831,7 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_material_slot(brna);
rna_def_dupli_object(brna);
RNA_define_animate_sdna(true);
+ rna_def_object_lodlevel(brna);
}
#endif
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index ac9af832671..b66cc11b51c 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -297,6 +297,7 @@ typedef struct wmNotifier {
#define ND_PARTICLE (27<<16)
#define ND_POINTCACHE (28<<16)
#define ND_PARENT (29<<16)
+#define ND_LOD (30<<16)
/* NC_MATERIAL Material */
#define ND_SHADING (30<<16)
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index b0555abbea4..bf7ac868d26 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -96,6 +96,7 @@
#include "KX_SoftBodyDeformer.h"
//#include "BL_ArmatureController.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BlenderWorldInfo.h"
#include "KX_KetsjiEngine.h"
@@ -1076,8 +1077,15 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
RAS_MeshObject *meshobj;
int lightlayer = blenderobj ? blenderobj->lay:(1<<20)-1; // all layers if no object.
- if ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL)
- return meshobj;
+ // Without checking names, we get some reuse we don't want that can cause
+ // problems with material LoDs.
+ if ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL) {
+ STR_String bge_name = meshobj->GetName();
+ STR_String blender_name = ((Mesh*)blenderobj->data)->id.name+2;
+ if (bge_name == blender_name)
+ return meshobj;
+ }
+
// Get DerivedMesh data
DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj);
DM_ensure_tessface(dm);
@@ -1989,6 +1997,24 @@ static KX_GameObject *gameobject_from_blenderobject(
// set transformation
gameobj->AddMesh(meshobj);
+
+ // gather levels of detail
+ if (BLI_countlist(&ob->lodlevels) > 1) {
+ LodLevel *lod = ((LodLevel*)ob->lodlevels.first)->next;
+ Mesh* lodmesh = mesh;
+ Object* lodmatob = ob;
+ gameobj->AddLodMesh(meshobj);
+ for (; lod; lod = lod->next) {
+ if (!lod->source || lod->source->type != OB_MESH) continue;
+ if (lod->flags & OB_LOD_USE_MESH) {
+ lodmesh = static_cast<Mesh*>(lod->source->data);
+ }
+ if (lod->flags & OB_LOD_USE_MAT) {
+ lodmatob = lod->source;
+ }
+ gameobj->AddLodMesh(BL_ConvertMesh(lodmesh, lodmatob, kxscene, converter, libloading));
+ }
+ }
// for all objects: check whether they want to
// respond to updates
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index 85fa0b2b3ce..36a21f0ede2 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -2047,6 +2047,10 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
cam->NodeUpdateGS(0.f);
scene->CalculateVisibleMeshes(m_rasterizer,cam);
+
+ // update levels of detail
+ scene->UpdateObjectLods();
+
scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
}
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index e06f7ab6633..780e9e01185 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -72,6 +72,8 @@ typedef unsigned long uint_ptr;
#include "NG_NetworkScene.h" //Needed for sendMessage()
#include "KX_ObstacleSimulation.h"
+#include "BKE_object.h"
+
#include "BL_ActionManager.h"
#include "BL_Action.h"
@@ -727,6 +729,43 @@ void KX_GameObject::RemoveMeshes()
m_meshes.clear();
}
+void KX_GameObject::AddLodMesh(RAS_MeshObject* mesh)
+{
+ m_lodmeshes.push_back(mesh);
+}
+
+void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos)
+{
+ // Handle dupligroups
+ if (this->m_pInstanceObjects) {
+ KX_GameObject * instob;
+ int count = this->m_pInstanceObjects->GetCount();
+ for (int i = 0; i < count; i++) {
+ instob = (KX_GameObject*)this->m_pInstanceObjects->GetValue(i);
+ instob->UpdateLod(cam_pos);
+ }
+ }
+
+ if (this->m_lodmeshes.empty()) return;
+
+ MT_Vector3 delta = this->NodeGetWorldPosition() - cam_pos;
+ float distance2 = delta.length2();
+
+ int level = 0;
+ Object *bob = this->GetBlenderObject();
+ LodLevel *lod = (LodLevel*) bob->lodlevels.first;
+ for (; lod; lod = lod->next, level++) {
+ if (!lod->source) level--;
+ if (!lod->next || lod->next->distance * lod->next->distance > distance2) break;
+ }
+
+ RAS_MeshObject *mesh = this->m_lodmeshes[level];
+
+ if (mesh != this->m_meshes[0]) {
+ this->GetScene()->ReplaceMesh(this, mesh, true, false);
+ }
+}
+
void KX_GameObject::UpdateTransform()
{
// HACK: saves function call for dynamic object, they are handled differently
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index dde3ff53299..26a8edef892 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -88,6 +88,7 @@ protected:
STR_String m_text;
int m_layer;
std::vector<RAS_MeshObject*> m_meshes;
+ std::vector<RAS_MeshObject*> m_lodmeshes;
SG_QList m_meshSlots; // head of mesh slots of this
struct Object* m_pBlenderObject;
struct Object* m_pBlenderGroupObject;
@@ -758,6 +759,23 @@ public:
}
/**
+ * Add a level of detail mesh to the object. These should
+ * be added in order.
+ */
+ void
+ AddLodMesh(
+ RAS_MeshObject* mesh
+ );
+
+ /**
+ * Updates the current lod level based on distance from camera.
+ */
+ void
+ UpdateLod(
+ MT_Vector3 &cam_pos
+ );
+
+ /**
* Pick out a mesh associated with the integer 'num'.
*/
RAS_MeshObject*
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index c685dcfe068..fc3ecd6c945 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -1330,6 +1330,9 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
scene->CalculateVisibleMeshes(m_rasterizer,cam);
+ // update levels of detail
+ scene->UpdateObjectLods();
+
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
SG_SetActiveStage(SG_STAGE_RENDER);
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 4fa51b48ab8..2aaaa1be66a 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -1694,6 +1694,19 @@ void KX_Scene::RenderFonts()
}
}
+void KX_Scene::UpdateObjectLods(void)
+{
+ KX_GameObject* gameobj;
+ MT_Vector3 cam_pos = this->m_active_camera->NodeGetWorldPosition();
+
+ for (int i = 0; i < this->GetObjectList()->GetCount(); i++) {
+ gameobj = (KX_GameObject*) GetObjectList()->GetValue(i);
+ if (!gameobj->GetCulled()){
+ gameobj->UpdateLod(cam_pos);
+ }
+ }
+}
+
void KX_Scene::UpdateObjectActivity(void)
{
if (m_activity_culling) {
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index edaa0663b22..5982a01d55b 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -545,6 +545,9 @@ public:
// Resume a suspended scene.
void Resume();
+
+ // Update the mesh for objects based on level of detail settings
+ void UpdateObjectLods(void);
// Update the activity box settings for objects in this scene, if needed.
void UpdateObjectActivity(void);