From 98a3ca91ed9aad07057e7de30c6c498d36f7f422 Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Sun, 5 Dec 2010 21:36:38 +0000
Subject: Support for func_move vertex groups.

---
 src/model/fragment.h | 22 +++++++++++++++++++++-
 src/model/mapfile.cc | 35 +++++++++++++++++++++++++++++++++++
 src/model/mapfile.h  |  1 +
 src/render/draw.cc   | 10 ++++++++--
 4 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/src/model/fragment.h b/src/model/fragment.h
index 31b7b96..58ff4bb 100644
--- a/src/model/fragment.h
+++ b/src/model/fragment.h
@@ -79,7 +79,7 @@ private:
 class FragmentGroup
 {
 public:
-	enum Type {None = 0, Rotate = 1, Door = 2 };
+	enum Type {None = 0, Rotate = 1, Move = 3, Door = 2 };
 
 	/// type definition for a list of model fragments
 	typedef std::list<Fragment *> Fragments;
@@ -105,6 +105,10 @@ public:
 	inline const float speed() const {
 		return group_speed;
 	}
+	
+	inline const float distance() const {
+		return group_distance;
+	}
 
 	inline const float scale() const {
 		return group_scale;
@@ -140,13 +144,28 @@ public:
 		group_location.assign(location);
 	}
 
+	/**
+	 * @brief rotation axis
+	 * For normal groups, this is the transformation matrix
+	 * For rotating groups axis->forward() is the axis of the rotation.
+	 * For movers, axis->forward() is the axis of movement. 
+	 */
 	inline void set_axis(const math::Axis &axis) {
 		group_axis.assign(axis);
 	}
 
+	/**
+	 * @brief movement speed
+	 * For rotating groups this is the number of degrees per second
+	 * For movers, this is the speed in units per second
+	 */
 	inline void set_speed(const float speed) {
 		group_speed = speed;
 	}
+	
+	inline void set_distance(const float distance) {
+		group_distance = distance;
+	}
 
 	inline void set_scale(const float scale) {
 		group_scale = scale;
@@ -170,6 +189,7 @@ private:
 	Type			group_type;
 	float			group_speed;
 	float			group_scale;
+	float			group_distance;
 
 	bool			group_transform;
 	bool			group_engine;
diff --git a/src/model/mapfile.cc b/src/model/mapfile.cc
index 09bb3af..f21484a 100644
--- a/src/model/mapfile.cc
+++ b/src/model/mapfile.cc
@@ -152,6 +152,7 @@ MapFile::MapFile()
 	warning_q2brush = false;
 	class_engine = false;
 	class_speed = 0;
+	class_distance = 0;
 
 	// the initial bounding box value is invalid: max and min are switched
 	class_box.assign(MAX_BOUNDS, -MAX_BOUNDS);
@@ -1123,6 +1124,7 @@ void MapFile::clear_bbox()
 	class_box.assign(MAX_BOUNDS, -MAX_BOUNDS);
 	class_axis.clear();
 	class_speed = 0;
+	class_distance = 0;
 	class_engine = false;
 }
 
@@ -1143,6 +1145,11 @@ void MapFile::load_fragmentgroup(Model *model, const FragmentGroup::Type class_t
 		}
 		group->set_speed(class_speed);
 		group->set_engine(class_engine);
+		
+	} else if (class_type == FragmentGroup::Move) {
+		group->set_speed(class_speed);
+		group->set_distance(class_distance);
+		group->set_engine(class_engine);
 	}
 
 	// expand bounding box
@@ -1351,6 +1358,34 @@ Model * MapFile::load(std::string const &name)
 			mapfile.load_fragmentgroup(model, FragmentGroup::None);
 			mapfile.clear_materials();
 
+		} else if (mapfile.got_classname("func_move")) {
+			mapfile.clear_bbox();
+			
+		} else if (mapfile.got_classend("func_move")) {
+			mapfile.load_fragmentgroup(model, FragmentGroup::Move);
+			mapfile.clear_materials();
+			
+		} else if (mapfile.in_class("func_move")) {
+
+			if (mapfile.got_key_axis(mapfile.class_axis)) {
+				continue;
+						
+			} else if (mapfile.got_key_int("spawnflags", u)) {
+				mapfile.class_engine  = spawnflag_isset(u, 4);
+				continue;
+				
+			} else if (mapfile.got_key_float("speed", s)) {
+				mapfile.class_speed = s * SCALE;
+				continue;
+				
+			} else if (mapfile.got_key_float("distance", s)) {
+				mapfile.class_distance = s * SCALE;
+				continue;
+
+			} else if (mapfile.got_key()) {
+				mapfile.unknown_key();
+			}
+
 		} else if (mapfile.got_classname("func_rotate")) {
 			mapfile.clear_bbox();
 
diff --git a/src/model/mapfile.h b/src/model/mapfile.h
index c78b56c..5e4bfd8 100644
--- a/src/model/mapfile.h
+++ b/src/model/mapfile.h
@@ -196,6 +196,7 @@ private:
 	math::BoundingBox3f	class_box;
 	math::Axis		class_axis;
 	float			class_speed;
+	float			class_distance;
 	bool			class_engine;
 
 	Materials		map_materials;
diff --git a/src/render/draw.cc b/src/render/draw.cc
index 30271f5..1e166b3 100644
--- a/src/render/draw.cc
+++ b/src/render/draw.cc
@@ -608,10 +608,16 @@ void draw_model_fragments(model::Model *model,
 			if (group->type() == model::FragmentGroup::Rotate) {
 				const float rotation_angle = math::degrees360f((group->engine() ? enginetime : core::application()->time()) * group->speed());
 				gl::rotate(-rotation_angle, group->axis().forward());
-			}  else {
+				
+			} else if (group->type() == model::FragmentGroup::Move ) {
+				const float speed = group->distance() / group->speed(); // units per second
+				math::Vector3f translation(group->axis().forward() * group->distance());
+				translation *= sinf((group->engine() ? enginetime : core::application()->time()) * M_PI * speed) * 0.5f + 0.5f;
+				 gl::translate(translation);
+			} else {
 				gl::multmatrix(group->axis());
 			}
-
+			
 			const float s = group->scale();
 			if (s)
 				gl::scale(s, s, s);
-- 
cgit v1.2.3