[Gtkradiant] r4792 - in GtkRadiant/trunk: docs/developer include
libs libs/math plugins/entity plugins/md3model radiant
svn-noreply at zerowing.idsoftware.com
svn-noreply at zerowing.idsoftware.com
Wed Sep 22 05:21:29 CDT 2004
Author: spog
Date: 2004-09-21 13:46:46 -0500 (Tue, 21 Sep 2004)
New Revision: 4792
Added:
GtkRadiant/trunk/libs/math/curve.cpp
GtkRadiant/trunk/libs/math/curve.h
Modified:
GtkRadiant/trunk/docs/developer/CHANGES
GtkRadiant/trunk/docs/developer/TODO
GtkRadiant/trunk/include/namespace.h
GtkRadiant/trunk/libs/eclasslib.h
GtkRadiant/trunk/libs/entitylib.h
GtkRadiant/trunk/libs/libs.vcproj
GtkRadiant/trunk/libs/math/frustum.h
GtkRadiant/trunk/libs/math/vector.h
GtkRadiant/trunk/libs/scenelib.h
GtkRadiant/trunk/libs/stringio.h
GtkRadiant/trunk/libs/traverselib.h
GtkRadiant/trunk/libs/undolib.h
GtkRadiant/trunk/plugins/entity/entity.cpp
GtkRadiant/trunk/plugins/entity/light.cpp
GtkRadiant/trunk/plugins/entity/namekeys.h
GtkRadiant/trunk/plugins/entity/static.cpp
GtkRadiant/trunk/plugins/entity/targetable.cpp
GtkRadiant/trunk/plugins/entity/targetable.h
GtkRadiant/trunk/plugins/md3model/md5.cpp
GtkRadiant/trunk/radiant/brush.h
GtkRadiant/trunk/radiant/eclass_doom3.cpp
GtkRadiant/trunk/radiant/entityinspector.cpp
GtkRadiant/trunk/radiant/mainframe.cpp
GtkRadiant/trunk/radiant/map.cpp
GtkRadiant/trunk/radiant/referencecache.cpp
GtkRadiant/trunk/radiant/texwindow.cpp
GtkRadiant/trunk/radiant/winding.cpp
GtkRadiant/trunk/radiant/winding.h
Log:
full doom3 'targetN' support; bug fixes; doom3 spline rendering
Modified: GtkRadiant/trunk/docs/developer/CHANGES
===================================================================
--- GtkRadiant/trunk/docs/developer/CHANGES 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/docs/developer/CHANGES 2004-09-21 18:46:46 UTC (rev 4792)
@@ -1,6 +1,31 @@
This is the changelog for developers, != changelog for the end user
that we distribute with the binaries. (see changelog)
+20/09/2004
+SPoG
+- Added basic rendering for 'curve_CatmullRomSpline' on doom3 entities.
+
+19/09/2004
+SPoG
+- Added basic rendering for 'curve_Nurbs' on doom3 entities.
+
+18/09/2004
+SPoG
+- Added doom3 entity-definition editor_usage* key support.
+- Added doom3 entity-definition editor_* key info to entity-inspector comments.
+- Added specialised attribute-entry in entity-inspector for boolean attributes.
+- Fixed crash in find-brush when entering the index of a fixed-size entity.
+- Added support for rendering doom3 'targetN' -> 'name' entity connections.
+- Changed connect-entities to use 'targetN' and 'name' keys on doom3 entities.
+- Improved handling of brushes with near-duplicate planes.
+- Fixed crash in snap-to-grid on brushes with non-contributing faces.
+
+17/09/2004
+Michael Schlueter
+- Fixed gcc build errors.
+SPoG
+- Fixed stability problems with doom3 brush-entities.
+
16/09/2004
SPoG
- Added automatic renaming of entity target/name keys for paste and import-map.
Modified: GtkRadiant/trunk/docs/developer/TODO
===================================================================
--- GtkRadiant/trunk/docs/developer/TODO 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/docs/developer/TODO 2004-09-21 18:46:46 UTC (rev 4792)
@@ -17,23 +17,20 @@
HIGH priority features
-Patch: add cap-texture fit-texture and natural-texture toolbar buttons
-Entity: support doom3 nurbs curves
+Brush: make edge/vertex/face dragging with QE tool select equal points
UI: change file-choosers to use GtkFileChooser on linux
-Brush: warn when a brush is dragged into a configuration with <0 volume
-Model: support doom3 .skin files
-Entity: add mouse-resizing for doom3 light_radius key
Model: add support for doom3 md5anim format
-HalfLife: disable patches
+Model: support doom3 .skin files
VFS: add ability to browse VFS from file-open dialogs.
-Entity: add specialised attribute-entry in entity-inspector for boolean/color/shader/list attribute types.
Installer: separate example-maps from main editor in linux installer.
Installer: enable q3 brush-primitives map support.
+Installer: add editor manual to linux installer
Textures: remove "shaders only" option for doom3
-Documentation: add manuals to installer
Map: support import/conversion of other map formats to current-game format
Map: create worldspawn first for .map format.
Brush: add texture painting feature
+Brush: warn when a brush is dragged into a configuration with <0 volume
+HalfLife: disable patches
HalfLife: add HL .mdl model loader.
HalfLife: add HL .spr support.
HalfLife: add support for Hammer texture-matrix.
@@ -41,25 +38,27 @@
Renderer: realtime doom3 lighting preview
Renderer: realtime doom3 shadows preview
Build System: add build-menu dmap support (doom3)
-Entity: support doom3 target* key
+Entity: support doom3 nurbs curves
+Entity: add mouse-resizing for doom3 light_radius key
+Entity: add specialised attribute-entry in entity-inspector for color/shader/list attribute types.
Entity: support doom3 light_radius key
-Entity: doom3 \entity key descriptions in 'n' window
Entity: light modification window ('j' in doomedit)
-Entity: entity names - generate new names for cloned/pasted entities
Entity: add rotate-tool support for 'angle' key
Entity: add 'angle' ui stuff to entity inspector
-Patch: support patchDef3 S/T tesselation
svn: remove install/ dir, create it during build process on win32
Editing: add resizing of patches with QE tool
+Patch: add cap-texture, fit-texture and natural-texture toolbar buttons
+Patch: support patchDef3 S/T tesselation
Patch: draw patches in wireframe from the back, make patches selectable from the back
Patch: add option for create-from-selection
+Patch: add merge-patches feature
Selection: convert-selection-to-brushes for entity selections
Selection: distinguish between entity and brush selections
Selection: 'add to selection' and 'subtract from selection' modifiers
Shortcuts: warn when duplicate shortcuts are registered
Selection: speed up 'invert selection' on large maps
-UI: migrate to GtkFileChooser for directory/file chooser dialogs
Selection: Finish scale manipulator (also, rescale/regenerate normals and re-tesselate patches).
+UI: migrate to GtkFileChooser for directory/file chooser dialogs
Clipper: Indicate which side is front and which is back.
Autosave/Snapshots: Add support for multiple files.
Directories: Prompt for engine path at startup if not set.
Modified: GtkRadiant/trunk/include/namespace.h
===================================================================
--- GtkRadiant/trunk/include/namespace.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/include/namespace.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -16,6 +16,7 @@
}
virtual void attach(const NameClosure& setName, const NameClosureClosure& attachObserver) = 0;
virtual void detach(const NameClosure& setName, const NameClosureClosure& detachObserver) = 0;
+ virtual void makeUnique(const char* name, const NameClosure& setName) const = 0;
};
class Namespaced
Modified: GtkRadiant/trunk/libs/eclasslib.h
===================================================================
--- GtkRadiant/trunk/libs/eclasslib.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/eclasslib.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -20,7 +20,8 @@
string_t m_type;
string_t m_key;
string_t m_name;
- EntityClassAttribute(const char* type, const char* key, const char* name) : m_type(type), m_key(key), m_name(name)
+ string_t m_description;
+ EntityClassAttribute(const char* type, const char* key, const char* name, const char* description = "") : m_type(type), m_key(key), m_name(name), m_description(description)
{
}
};
Modified: GtkRadiant/trunk/libs/entitylib.h
===================================================================
--- GtkRadiant/trunk/libs/entitylib.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/entitylib.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -246,7 +246,7 @@
typedef Closure1<const char*> KeyObserver;
-class KeyValue : public UndoableObjectObserver
+class KeyValue
{
typedef UnsortedSet<KeyObserver> KeyObservers;
@@ -258,7 +258,7 @@
public:
KeyValue(const char* string)
- : m_refcount(0), m_string(string), m_undo(m_string, *this)
+ : m_refcount(0), m_string(string), m_undo(m_string, UndoImportCaller(*this))
{
notify();
}
@@ -326,13 +326,16 @@
}
}
- void postUndoImport()
+ void undoImport(const string_t& string)
{
+ m_string = string;
+
notify();
}
+ typedef MemberCaller1<KeyValue, const string_t&>::Caller<&KeyValue::undoImport> UndoImportCaller;
};
-class EntityKeyValues : public Entity, public UndoableObjectObserver
+class EntityKeyValues : public Entity
{
public:
typedef KeyValue Value;
@@ -348,10 +351,11 @@
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
static Counter* m_counter;
- typedef UnsortedMap<string_t, refcounted_ptr<KeyValue> > KeyValues;
- KeyValues m_keyvalues;
+ typedef refcounted_ptr<KeyValue> KeyValuePtr;
+ typedef UnsortedMap<string_t, KeyValuePtr > KeyValues;
+ KeyValues m_keyValues;
- typedef std::set<Observer*> Observers;
+ typedef UnsortedSet<Observer*> Observers;
Observers m_observers;
ObservedUndoableObject<KeyValues> m_undo;
@@ -359,66 +363,104 @@
EntityClass* m_eclass;
- void notify_insert(const char* key, Value& value)
+ bool m_observerMutex;
+
+ void notifyInsert(const char* key, Value& value)
{
+ m_observerMutex = true;
for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
{
(*i)->insert(key, value);
}
+ m_observerMutex = false;
}
- void notify_erase(const char* key, Value& value)
+ void notifyErase(const char* key, Value& value)
{
+ m_observerMutex = true;
for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
{
(*i)->erase(key, value);
}
+ m_observerMutex = false;
}
- void notify_insert_all()
+ void forEachKeyValue_notifyInsert()
{
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
- notify_insert((*i).first.c_str(), *(*i).second);
+ notifyInsert((*i).first.c_str(), *(*i).second);
}
}
- void notify_erase_all()
+ void forEachKeyValue_notifyErase()
{
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
- notify_erase((*i).first.c_str(), *(*i).second);
+ notifyErase((*i).first.c_str(), *(*i).second);
}
}
- void insert(const char* key, const char* value)
+ void insert(const char* key, const KeyValuePtr& keyValue)
{
- m_undo.save();
- Value* keyValue = new KeyValue(value);
- notify_insert(key, *keyValue);
- KeyValues::iterator i = m_keyvalues.insert(KeyValues::value_type(key, keyValue));
+ KeyValues::iterator i = m_keyValues.insert(KeyValues::value_type(key, keyValue));
+ notifyInsert(key, *(*i).second);
+
if(m_instanced)
{
(*i).second->instanceAttach(m_undo.map());
}
- m_entityKeyValueChanged();
}
+
+ void insert(const char* key, const char* value)
+ {
+ KeyValues::iterator i = m_keyValues.find(key);
+ if(i != m_keyValues.end())
+ {
+ (*i).second->assign(value);
+ }
+ else
+ {
+ m_undo.save();
+ insert(key, new KeyValue(value));
+ }
+ }
+
void erase(KeyValues::iterator i)
{
- m_undo.save();
if(m_instanced)
{
(*i).second->instanceDetach(m_undo.map());
}
- notify_erase((*i).first.c_str(), *(*i).second);
- m_keyvalues.erase(i);
- m_entityKeyValueChanged();
+
+ string_t key((*i).first);
+ KeyValuePtr value((*i).second);
+ m_keyValues.erase(i);
+ notifyErase(key.c_str(), *value);
}
+ void erase(const char* key)
+ {
+ KeyValues::iterator i = m_keyValues.find(key);
+ if(i != m_keyValues.end())
+ {
+ m_undo.save();
+ erase(i);
+ }
+ }
+
public:
- EntityKeyValues(EntityClass* eclass) : m_eclass(eclass), m_undo(m_keyvalues, *this), m_instanced(false)
+ EntityKeyValues(EntityClass* eclass) :
+ m_eclass(eclass),
+ m_undo(m_keyValues, UndoImportCaller(*this)),
+ m_instanced(false),
+ m_observerMutex(false)
{
}
- EntityKeyValues(const EntityKeyValues& other) : m_eclass(&other.eclass()), m_undo(m_keyvalues, *this), m_instanced(false)
+ EntityKeyValues(const EntityKeyValues& other) :
+ m_eclass(&other.eclass()),
+ m_undo(m_keyValues, UndoImportCaller(*this)),
+ m_instanced(false),
+ m_observerMutex(false)
{
- for(KeyValues::const_iterator i = other.m_keyvalues.begin(); i != other.m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = other.m_keyValues.begin(); i != other.m_keyValues.end(); ++i)
{
insert((*i).first.c_str(), (*i).second->c_str());
}
@@ -434,38 +476,38 @@
m_counter = counter;
}
- void preUndoImport()
+ void undoImport(const KeyValues& keyValues)
{
- notify_erase_all();
- if(m_instanced)
+ for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end();)
{
- forEachKeyValue_instanceDetach(m_undo.map());
+ erase(i++);
}
- }
- void postUndoImport()
- {
- if(m_instanced)
+
+ for(KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i)
{
- forEachKeyValue_instanceAttach(m_undo.map());
+ insert((*i).first.c_str(), (*i).second);
}
- notify_insert_all();
+
m_entityKeyValueChanged();
}
+ typedef MemberCaller1<EntityKeyValues, const KeyValues&>::Caller<&EntityKeyValues::undoImport> UndoImportCaller;
void attach(Observer& observer)
{
+ RADIANT_ASSERT(!m_observerMutex, "observer cannot be attached during iteration");
RADIANT_ASSERT(m_observers.find(&observer) == m_observers.end(), "observer cannot be attached");
m_observers.insert(&observer);
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
observer.insert((*i).first.c_str(), *(*i).second);
}
}
void detach(Observer& observer)
{
+ RADIANT_ASSERT(!m_observerMutex, "observer cannot be detached during iteration");
RADIANT_ASSERT(m_observers.find(&observer) != m_observers.end(), "observer cannot be detached");
m_observers.erase(&observer);
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
observer.erase((*i).first.c_str(), *(*i).second);
}
@@ -473,14 +515,14 @@
void forEachKeyValue_instanceAttach(MapFile* map)
{
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
(*i).second->instanceAttach(map);
}
}
void forEachKeyValue_instanceDetach(MapFile* map)
{
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
(*i).second->instanceDetach(map);
}
@@ -516,7 +558,7 @@
}
void accept(Visitor& visitor) const
{
- for(KeyValues::const_iterator i = m_keyvalues.begin(); i != m_keyvalues.end(); ++i)
+ for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
visitor.visit((*i).first.c_str(), (*i).second->c_str());
}
@@ -525,29 +567,18 @@
{
if(value[0] == '\0')
{
- KeyValues::iterator i = m_keyvalues.find(key);
- if(i != m_keyvalues.end())
- {
- erase(i);
- }
+ erase(key);
}
else
{
- KeyValues::iterator i = m_keyvalues.find(key);
- if(i != m_keyvalues.end())
- {
- (*i).second->assign(value);
- }
- else
- {
- insert(key, value);
- }
+ insert(key, value);
}
+ m_entityKeyValueChanged();
}
const char* valueforkey(const char* key) const
{
- KeyValues::const_iterator i = m_keyvalues.find(key);
- if(i != m_keyvalues.end())
+ KeyValues::const_iterator i = m_keyValues.find(key);
+ if(i != m_keyValues.end())
{
return (*i).second->c_str();
}
Modified: GtkRadiant/trunk/libs/libs.vcproj
===================================================================
--- GtkRadiant/trunk/libs/libs.vcproj 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/libs.vcproj 2004-09-21 18:46:46 UTC (rev 4792)
@@ -133,6 +133,12 @@
RelativePath=".\math\matrix.h">
</File>
<File
+ RelativePath=".\math\nurbscurve.cpp">
+ </File>
+ <File
+ RelativePath=".\math\nurbscurve.h">
+ </File>
+ <File
RelativePath=".\math\pi.cpp">
</File>
<File
Added: GtkRadiant/trunk/libs/math/curve.cpp
===================================================================
--- GtkRadiant/trunk/libs/math/curve.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/math/curve.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -0,0 +1,3 @@
+
+#include "curve.h"
+
Property changes on: GtkRadiant/trunk/libs/math/curve.cpp
___________________________________________________________________
Name: svn:eol-style
+ native
Added: GtkRadiant/trunk/libs/math/curve.h
===================================================================
--- GtkRadiant/trunk/libs/math/curve.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/math/curve.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -0,0 +1,5 @@
+
+#if !defined(_INCLUDED_CURVE_H_)
+#define _INCLUDED_CURVE_H_
+
+#endif
Property changes on: GtkRadiant/trunk/libs/math/curve.h
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: GtkRadiant/trunk/libs/math/frustum.h
===================================================================
--- GtkRadiant/trunk/libs/math/frustum.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/math/frustum.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -83,7 +83,7 @@
bool b1 = ClipPlane::compare(*next);
if(b0 ^ b1)
{
- *out = vector4_subtract(*next, *i);
+ *out = vector4_subtracted(*next, *i);
double scale = ClipPlane::scale(*i, *out);
@@ -197,7 +197,7 @@
const bool index = CLIP_X_LT_W(p0);
if(index ^ CLIP_X_LT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[0] - p0[3]) / (clip[3] - clip[0]);
@@ -216,7 +216,7 @@
const bool index = CLIP_X_GT_W(p0);
if(index ^ CLIP_X_GT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[0] + p0[3]) / (-clip[3] - clip[0]);
@@ -235,7 +235,7 @@
const bool index = CLIP_Y_LT_W(p0);
if(index ^ CLIP_Y_LT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[1] - p0[3]) / (clip[3] - clip[1]);
@@ -254,7 +254,7 @@
const bool index = CLIP_Y_GT_W(p0);
if(index ^ CLIP_Y_GT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[1] + p0[3]) / (-clip[3] - clip[1]);
@@ -273,7 +273,7 @@
const bool index = CLIP_Z_LT_W(p0);
if(index ^ CLIP_Z_LT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[2] - p0[3]) / (clip[3] - clip[2]);
@@ -292,7 +292,7 @@
const bool index = CLIP_Z_GT_W(p0);
if(index ^ CLIP_Z_GT_W(p1))
{
- Vector4 clip(vector4_subtract(p1, p0));
+ Vector4 clip(vector4_subtracted(p1, p0));
double scale = (p0[2] + p0[3]) / (-clip[3] - clip[2]);
Modified: GtkRadiant/trunk/libs/math/vector.h
===================================================================
--- GtkRadiant/trunk/libs/math/vector.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/math/vector.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -383,6 +383,33 @@
}
template<typename Element, typename OtherElement>
+inline BasicVector3<Element> vector3_divided(const BasicVector3<Element>& self, const OtherElement& divisor)
+{
+ return BasicVector3<Element>(
+ Element(self.x() / divisor),
+ Element(self.y() / divisor),
+ Element(self.z() / divisor)
+ );
+}
+template<typename Element, typename OtherElement>
+inline BasicVector3<Element> operator/(const BasicVector3<Element>& self, const OtherElement& divisor)
+{
+ return vector3_divided(self, divisor);
+}
+template<typename Element, typename OtherElement>
+inline void vector3_divide(BasicVector3<Element>& self, const OtherElement& divisor)
+{
+ self.x() /= static_cast<Element>(divisor);
+ self.y() /= static_cast<Element>(divisor);
+ self.z() /= static_cast<Element>(divisor);
+}
+template<typename Element, typename OtherElement>
+inline void operator/=(BasicVector3<Element>& self, const OtherElement& divisor)
+{
+ vector3_divide(self, divisor);
+}
+
+template<typename Element, typename OtherElement>
inline double vector3_dot(const BasicVector3<Element>& self, const BasicVector3<OtherElement>& other)
{
return self.x() * other.x() + self.y() * other.y() + self.z() * other.z();
@@ -586,9 +613,129 @@
return reinterpret_cast<const Vector3&>(self);
}
-inline Vector4 vector4_subtract(const Vector4& self, const Vector4& other)
+inline Vector4 vector4_added(const Vector4& self, const Vector4& other)
{
- return Vector4(self.x() - other.x(), self.y() - other.y(), self.z() - other.z(), self.w() - other.w());
+ return Vector4(
+ float(self.x() + other.x()),
+ float(self.y() + other.y()),
+ float(self.z() + other.z()),
+ float(self.w() + other.w())
+ );
}
+inline Vector4 operator+(const Vector4& self, const Vector4& other)
+{
+ return vector4_added(self, other);
+}
+inline void vector4_add(Vector4& self, const Vector4& other)
+{
+ self.x() += static_cast<float>(other.x());
+ self.y() += static_cast<float>(other.y());
+ self.z() += static_cast<float>(other.z());
+ self.w() += static_cast<float>(other.w());
+}
+inline void operator+=(Vector4& self, const Vector4& other)
+{
+ vector4_add(self, other);
+}
+inline Vector4 vector4_subtracted(const Vector4& self, const Vector4& other)
+{
+ return Vector4(
+ float(self.x() - other.x()),
+ float(self.y() - other.y()),
+ float(self.z() - other.z()),
+ float(self.w() - other.w())
+ );
+}
+inline Vector4 operator-(const Vector4& self, const Vector4& other)
+{
+ return vector4_subtracted(self, other);
+}
+inline void vector4_subtract(Vector4& self, const Vector4& other)
+{
+ self.x() -= static_cast<float>(other.x());
+ self.y() -= static_cast<float>(other.y());
+ self.z() -= static_cast<float>(other.z());
+ self.w() -= static_cast<float>(other.w());
+}
+inline void operator-=(Vector4& self, const Vector4& other)
+{
+ vector4_subtract(self, other);
+}
+
+inline Vector4 vector4_scaled(const Vector4& self, const Vector4& other)
+{
+ return Vector4(
+ float(self.x() * other.x()),
+ float(self.y() * other.y()),
+ float(self.z() * other.z()),
+ float(self.w() * other.w())
+ );
+}
+inline Vector4 operator*(const Vector4& self, const Vector4& other)
+{
+ return vector4_scaled(self, other);
+}
+inline void vector4_scale(Vector4& self, const Vector4& other)
+{
+ self.x() *= static_cast<float>(other.x());
+ self.y() *= static_cast<float>(other.y());
+ self.z() *= static_cast<float>(other.z());
+ self.w() *= static_cast<float>(other.w());
+}
+inline void operator*=(Vector4& self, const Vector4& other)
+{
+ vector4_scale(self, other);
+}
+
+inline Vector4 vector4_scaled(const Vector4& self, const float& scale)
+{
+ return Vector4(
+ float(self.x() * scale),
+ float(self.y() * scale),
+ float(self.z() * scale),
+ float(self.w() * scale)
+ );
+}
+inline Vector4 operator*(const Vector4& self, const float& scale)
+{
+ return vector4_scaled(self, scale);
+}
+inline void vector4_scale(Vector4& self, const float& scale)
+{
+ self.x() *= static_cast<float>(scale);
+ self.y() *= static_cast<float>(scale);
+ self.z() *= static_cast<float>(scale);
+ self.w() *= static_cast<float>(scale);
+}
+inline void operator*=(Vector4& self, const float& scale)
+{
+ vector4_scale(self, scale);
+}
+
+inline Vector4 vector4_divided(const Vector4& self, const float& divisor)
+{
+ return Vector4(
+ float(self.x() / divisor),
+ float(self.y() / divisor),
+ float(self.z() / divisor),
+ float(self.w() / divisor)
+ );
+}
+inline Vector4 operator/(const Vector4& self, const float& divisor)
+{
+ return vector4_divided(self, divisor);
+}
+inline void vector4_divide(Vector4& self, const float& divisor)
+{
+ self.x() /= static_cast<float>(divisor);
+ self.y() /= static_cast<float>(divisor);
+ self.z() /= static_cast<float>(divisor);
+ self.w() /= static_cast<float>(divisor);
+}
+inline void operator/=(Vector4& self, const float& divisor)
+{
+ vector4_divide(self, divisor);
+}
+
#endif
Modified: GtkRadiant/trunk/libs/scenelib.h
===================================================================
--- GtkRadiant/trunk/libs/scenelib.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/scenelib.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -35,7 +35,8 @@
m_data(0),
m_end(0),
m_capacity(0)
- {}
+ {
+ }
Stack(const value_type n) :
m_data(0),
m_capacity(0),
Modified: GtkRadiant/trunk/libs/stringio.h
===================================================================
--- GtkRadiant/trunk/libs/stringio.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/stringio.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -7,11 +7,6 @@
#include <stdio.h>
#include <stdlib.h>
-inline bool string_read_vector(const char* string, Vector3& vector3)
-{
- return sscanf(string, "%f %f %f", &vector3[0], &vector3[1], &vector3[2]) == 3;
-}
-
inline float string_read_float(const char* string)
{
return static_cast<float>(atof(string));
@@ -22,20 +17,49 @@
return atoi(string);
}
+inline bool string_parse_float(const char* string, float& f)
+{
+ return sscanf(string, "%f", &f) == 1;
+}
+
+inline bool string_parse_double(const char* string, double& f)
+{
+ return sscanf(string, "%lf", &f) == 1;
+}
+
+inline bool string_parse_vector(const char* string, Vector3& vector3)
+{
+ return sscanf(string, "%f %f %f", &vector3[0], &vector3[1], &vector3[2]) == 3;
+}
+
+inline bool string_parse_int(const char* string, int& i)
+{
+ return sscanf(string, "%i", &i) == 1;
+}
+
+inline bool string_parse_size(const char* string, std::size_t& i)
+{
+ return sscanf(string, "%u", &i) == 1;
+}
+
inline bool Tokeniser_getFloat(Tokeniser* tokeniser, float& f)
{
- return sscanf(tokeniser->getToken(), "%f", &f) == 1;
+ return string_parse_float(tokeniser->getToken(), f);
}
inline bool Tokeniser_getDouble(Tokeniser* tokeniser, double& f)
{
- return sscanf(tokeniser->getToken(), "%lf", &f) == 1;
+ return string_parse_double(tokeniser->getToken(), f);
}
inline bool Tokeniser_getInteger(Tokeniser* tokeniser, int& i)
{
- return sscanf(tokeniser->getToken(), "%i", &i) == 1;
+ return string_parse_int(tokeniser->getToken(), i);
}
+inline bool Tokeniser_getSize(Tokeniser* tokeniser, std::size_t& i)
+{
+ return string_parse_size(tokeniser->getToken(), i);
+}
#endif
Modified: GtkRadiant/trunk/libs/traverselib.h
===================================================================
--- GtkRadiant/trunk/libs/traverselib.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/traverselib.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -114,7 +114,9 @@
{
#if 1 // optimised change-tracking using diff algorithm
if(m_observer)
+ {
nodeset_diff(m_children, other.m_children, m_observer);
+ }
copy(other);
#else
ObservedNodeSet tmp(other);
@@ -147,14 +149,18 @@
m_children.insert(n);
if(m_observer)
+ {
m_observer->insert(n);
+ }
}
void erase(scene::Node* n)
{
RADIANT_ASSERT(m_children.find(n) != m_children.end(), "TraversableSet::erase - failed to find element");
if(m_observer)
+ {
m_observer->erase(n);
+ }
m_children.erase(n);
}
@@ -165,7 +171,7 @@
{
// post-increment the iterator
(*i++)->traverse(w);
- // the Walker can safely remove the node from
+ // the Walker can safely remove the current node from
// this container without invalidating the iterator
}
}
@@ -220,17 +226,27 @@
class traverse_node : public scene::Traversable
{
public:
- traverse_node()
- : m_node(0), m_observer(0)
- {}
+ traverse_node() : m_node(0), m_observer(0)
+ {
+ }
// traverse
void attach(Observer* observer)
{
+ RADIANT_ASSERT(m_observer == 0, "traverse_node::attach - cannot attach observer");
m_observer = observer;
+ if(m_node != 0)
+ {
+ m_observer->insert(m_node);
+ }
}
void detach(Observer* observer)
{
+ RADIANT_ASSERT(m_observer == observer, "traverse_node::detach - cannot detach observer");
+ if(m_node != 0)
+ {
+ m_observer->erase(m_node);
+ }
m_observer = 0;
}
void insert(scene::Node* n)
@@ -241,14 +257,18 @@
n->IncRef();
if(m_observer)
+ {
m_observer->insert(n);
+ }
}
void erase(scene::Node* n)
{
RADIANT_ASSERT(m_node == n, "traverse_node::erase - failed to find element");
if(m_observer)
+ {
m_observer->erase(n);
+ }
m_node = 0;
n->DecRef();
@@ -256,7 +276,9 @@
void traverse(scene::Traversable::Walker& w)
{
if(m_node)
+ {
m_node->traverse(w);
+ }
}
scene::Node* get()
Modified: GtkRadiant/trunk/libs/undolib.h
===================================================================
--- GtkRadiant/trunk/libs/undolib.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/libs/undolib.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -5,14 +5,8 @@
#include "iundo.h"
#include "imap.h"
#include "warnings.h"
+#include "functional.h"
-class UndoableObjectObserver
-{
-public:
- virtual void preUndoImport() {};
- virtual void postUndoImport() {};
-};
-
template<typename Copyable>
class BasicUndoData : public UndoData
{
@@ -35,19 +29,21 @@
};
-template <class object_type>
+template <typename Copyable>
class ObservedUndoableObject : public Undoable
{
-private:
- object_type& m_object;
- UndoableObjectObserver& m_observer;
+ typedef Closure1<const Copyable&> ImportClosure;
+
+ Copyable& m_object;
+ ImportClosure m_importClosure;
UndoObserver* m_undoQueue;
MapFile* m_map;
public:
- ObservedUndoableObject<object_type>(object_type& object, UndoableObjectObserver& observer)
- : m_object(object), m_observer(observer), m_undoQueue(0), m_map(0)
- {}
+ ObservedUndoableObject<Copyable>(Copyable& object, const ImportClosure& importClosure)
+ : m_object(object), m_importClosure(importClosure), m_undoQueue(0), m_map(0)
+ {
+ }
~ObservedUndoableObject()
{
}
@@ -83,26 +79,24 @@
UndoData* undoExport() const
{
- return new BasicUndoData<object_type>(m_object);
+ return new BasicUndoData<Copyable>(m_object);
}
void undoImport(const UndoData* state)
{
save();
- m_observer.preUndoImport();
- m_object = (static_cast<const BasicUndoData<object_type>*>(state))->get();
- m_observer.postUndoImport();
+ m_importClosure((static_cast<const BasicUndoData<Copyable>*>(state))->get());
}
};
-template <class object_type>
+template <class Copyable>
class UndoableObject : public Undoable
{
- object_type& m_object;
+ Copyable& m_object;
UndoObserver* m_undoQueue;
MapFile* m_map;
public:
- UndoableObject(object_type& object)
+ UndoableObject(Copyable& object)
: m_object(object), m_undoQueue(0), m_map(0)
{}
~UndoableObject()
@@ -135,12 +129,12 @@
UndoData* undoExport() const
{
- return new BasicUndoData<object_type>(m_object);
+ return new BasicUndoData<Copyable>(m_object);
}
void undoImport(const UndoData* state)
{
save();
- m_object = (static_cast<const BasicUndoData<object_type>*>(state))->get();
+ m_object = (static_cast<const BasicUndoData<Copyable>*>(state))->get();
}
};
Modified: GtkRadiant/trunk/plugins/entity/entity.cpp
===================================================================
--- GtkRadiant/trunk/plugins/entity/entity.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/entity.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -12,6 +12,7 @@
#include "targetable.h"
#include "uniquenames.h"
#include "namekeys.h"
+#include "stringstream.h"
#if 0
#include "registry.h"
@@ -129,6 +130,26 @@
bool g_newLightDraw = true;
bool g_lightRadii = false;
+class ConnectEntities
+{
+public:
+ const scene::Path& m_e1;
+ const scene::Path& m_e2;
+ ConnectEntities(const scene::Path& e1, const scene::Path& e2) : m_e1(e1), m_e2(e2)
+ {
+ }
+ void connect(const char* name)
+ {
+ m_e1.top()->m_entity->setkeyvalue("target", name);
+ m_e2.top()->m_entity->setkeyvalue("targetname", name);
+ }
+ typedef MemberCaller1<ConnectEntities, const char*>::Caller<&ConnectEntities::connect> ConnectCaller;
+};
+
+void EntitySetTargetTargetname(const char* name)
+{
+}
+
class Quake3EntityCreator : public EntityCreator
{
public:
@@ -146,36 +167,6 @@
}
void connectEntities(const scene::Path& e1, const scene::Path& e2)
{
- class entity_maxtarget : public scene::Graph::Walker
- {
- unsigned int& m_maxtarget;
- public:
- entity_maxtarget(unsigned int& maxtarget)
- : m_maxtarget(maxtarget)
- {
- }
- bool pre(const scene::Path& path, scene::Instance& instance)
- {
- if(path.top()->m_entity)
- {
- const char* value = path.top()->m_entity->valueforkey("target");
- if (value && value[0])
- {
- unsigned int targetnum = atoi(value+1);
- if (targetnum > m_maxtarget)
- m_maxtarget = targetnum;
- }
- }
- return true;
- }
- void post(const scene::Path& path, scene::Instance& instance)
- {
- }
- };
-
- char newtarget[16];
- unsigned int maxtarget = 0; // highest t# value in the map
-
if(e1.top()->m_entity == 0
|| e2.top()->m_entity == 0)
return;
@@ -185,15 +176,30 @@
return;
}
+ if(g_gameType == eGameTypeDoom3)
{
- entity_maxtarget walker(maxtarget);
- GlobalSceneGraph().traverse(walker);
+ StringOutputStream key(16);
+ for(unsigned int i = 0; ; ++i)
+ {
+ key << "target";
+ if(i != 0)
+ {
+ key << i;
+ }
+ const char* value = e1.top()->m_entity->valueforkey(key.c_str());
+ if(string_empty(value))
+ {
+ e1.top()->m_entity->setkeyvalue(key.c_str(), e2.top()->m_entity->valueforkey("name"));
+ break;
+ }
+ key.clear();
+ }
}
-
- sprintf (newtarget, "t%i", maxtarget+1);
-
- e1.top()->m_entity->setkeyvalue("target", newtarget);
- e2.top()->m_entity->setkeyvalue("targetname", newtarget);
+ else
+ {
+ ConnectEntities connect(e1, e2);
+ GlobalNamespace().makeUnique("t1", ConnectEntities::ConnectCaller(connect));
+ }
}
void setLightRadii(bool lightRadii)
{
Modified: GtkRadiant/trunk/plugins/entity/light.cpp
===================================================================
--- GtkRadiant/trunk/plugins/entity/light.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/light.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -542,14 +542,14 @@
void lightRadiusChanged(const char* value)
{
- m_useRadiusKey = string_read_vector(value, m_radius);
+ m_useRadiusKey = string_parse_vector(value, m_radius);
m_changed();
}
typedef MemberCaller1<Doom3LightRadius, const char*>::Caller<&Doom3LightRadius::lightRadiusChanged> LightRadiusChangedCaller;
void lightCenterChanged(const char* value)
{
- m_useCenterKey = string_read_vector(value, m_center);
+ m_useCenterKey = string_parse_vector(value, m_center);
}
typedef MemberCaller1<Doom3LightRadius, const char*>::Caller<&Doom3LightRadius::lightCenterChanged> LightCenterChangedCaller;
};
Modified: GtkRadiant/trunk/plugins/entity/namekeys.h
===================================================================
--- GtkRadiant/trunk/plugins/entity/namekeys.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/namekeys.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -3,6 +3,7 @@
#define _INCLUDED_NAMEKEYS_H_
#include <stdio.h>
+#include <map>
#include "staticinstance.h"
#include "entitylib.h"
#include "namespace.h"
@@ -37,6 +38,40 @@
KeyIsNameFunc m_keyIsName;
NameKeys(const NameKeys& other);
NameKeys& operator=(const NameKeys& other);
+
+ typedef std::map<string_t, EntityKeyValues::Value*> KeyValues;
+ KeyValues m_keyValues;
+
+ void insertName(const char* key, EntityKeyValues::Value& value)
+ {
+ if(m_namespace != 0 && m_keyIsName(key))
+ {
+ //globalOutputStream() << "insert " << key << "\n";
+ m_namespace->attach(KeyValueAssignCaller(value), KeyValueAttachCaller(value));
+ }
+ }
+ void eraseName(const char* key, EntityKeyValues::Value& value)
+ {
+ if(m_namespace != 0 && m_keyIsName(key))
+ {
+ //globalOutputStream() << "erase " << key << "\n";
+ m_namespace->detach(KeyValueAssignCaller(value), KeyValueDetachCaller(value));
+ }
+ }
+ void insertAll()
+ {
+ for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
+ {
+ insertName((*i).first.c_str(), *(*i).second);
+ }
+ }
+ void eraseAll()
+ {
+ for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
+ {
+ eraseName((*i).first.c_str(), *(*i).second);
+ }
+ }
public:
NameKeys(EntityKeyValues& entity) : m_namespace(0), m_entity(entity), m_keyIsName(Static<KeyIsName>::instance().m_keyIsName)
{
@@ -48,31 +83,25 @@
}
void setNamespace(Namespace& space)
{
- m_entity.detach(*this);
+ eraseAll();
m_namespace = &space;
- m_entity.attach(*this);
+ insertAll();
}
void setKeyIsName(KeyIsNameFunc keyIsName)
{
- m_entity.detach(*this);
+ eraseAll();
m_keyIsName = keyIsName;
- m_entity.attach(*this);
+ insertAll();
}
void insert(const char* key, EntityKeyValues::Value& value)
{
- if(m_namespace != 0 && m_keyIsName(key))
- {
- //globalOutputStream() << "insert " << key << "\n";
- m_namespace->attach(KeyValueAssignCaller(value), KeyValueAttachCaller(value));
- }
+ m_keyValues.insert(KeyValues::value_type(key, &value));
+ insertName(key, value);
}
void erase(const char* key, EntityKeyValues::Value& value)
{
- if(m_namespace != 0 && m_keyIsName(key))
- {
- //globalOutputStream() << "erase " << key << "\n";
- m_namespace->detach(KeyValueAssignCaller(value), KeyValueDetachCaller(value));
- }
+ eraseName(key, value);
+ m_keyValues.erase(key);
}
};
Modified: GtkRadiant/trunk/plugins/entity/static.cpp
===================================================================
--- GtkRadiant/trunk/plugins/entity/static.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/static.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -60,11 +60,9 @@
public:
FuncStaticOrigin(TraversableSet& set, Origin& origin) : m_set(set), m_observer(0), m_origin(origin), m_enabled(false)
{
- m_set.attach(this);
}
~FuncStaticOrigin()
{
- m_set.detach(this);
}
void enable()
@@ -121,57 +119,183 @@
}
};
-class FuncStaticModelNode : public scene::Traversable
+#include "math/curve.h"
+
+class RenderableCurve : public OpenGLRenderable
{
- scene::Traversable& m_set;
- scene::Node* m_model;
- bool m_enabled;
public:
- FuncStaticModelNode(scene::Traversable& set) : m_set(set), m_model(0), m_enabled(false)
+ std::vector<PointVertex> m_vertices;
+ void Render(ERenderState state) const
{
+ pointvertex_gl_array(&m_vertices.front());
+ qglDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
}
+};
- void setEnabled(bool enabled)
+void plotBasisFunction(std::size_t numSegments, int point, int degree)
+{
+ Knots knots;
+ KnotVector_openUniform(knots, 4, degree);
+
+ globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
+ for(Knots::iterator i = knots.begin(); i != knots.end(); ++i)
{
- if(m_model != 0)
+ globalOutputStream() << " " << *i;
+ }
+ globalOutputStream() << "\n";
+ globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
+ for(std::size_t i = 1; i < numSegments; ++i)
+ {
+ float t = (1.0 / double(numSegments)) * double(i);
+ globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
+ }
+ globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
+}
+
+class NURBSCurve
+{
+public:
+ ControlPoints m_controlPoints;
+ NURBSWeights m_weights;
+ Knots m_knots;
+ RenderableCurve m_renderCurve;
+
+ bool parseCurve(const char* value)
+ {
+ StringTokeniser tokeniser(value, " ");
+
+ std::size_t size;
+ if(!string_parse_size(tokeniser.getToken(), size))
{
- if(m_enabled && !enabled)
+ return false;
+ }
+
+ if(size < 3)
+ {
+ return false;
+ }
+ const int BSpline_degree = 3;
+
+ m_weights.allocate(size);
+ for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
+ {
+ (*i) = 1;
+ }
+
+ m_controlPoints.allocate(size);
+
+ if(!string_equal(tokeniser.getToken(), "("))
+ {
+ return false;
+ }
+ for(ControlPoints::iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
+ {
+ if(!string_parse_float(tokeniser.getToken(), (*i).x())
+ || !string_parse_float(tokeniser.getToken(), (*i).y())
+ || !string_parse_float(tokeniser.getToken(), (*i).z()))
{
- m_set.erase(m_model);
+ return false;
}
- else if(!m_enabled && enabled)
- {
- m_set.insert(m_model);
- }
}
- m_enabled = enabled;
+ if(!string_equal(tokeniser.getToken(), ")"))
+ {
+ return false;
+ }
+
+ KnotVector_openUniform(m_knots, m_controlPoints.size(), BSpline_degree);
+
+ const std::size_t numSegments = 64;
+ m_renderCurve.m_vertices.resize(numSegments + 1);
+ m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPoints[0]);
+ for(std::size_t i = 1; i < numSegments; ++i)
+ {
+ m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(m_controlPoints, m_weights, m_knots, BSpline_degree, (1.0 / double(numSegments)) * double(i)));
+ }
+ m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPoints[m_controlPoints.size() - 1]);
+
+ //plotBasisFunction(8, 0, BSpline_degree);
+
+ return true;
}
- void insert(scene::Node* node)
+ void curveChanged(const char* value)
{
- RADIANT_ASSERT(m_model == 0, "func_error");
- m_model = node;
- if(m_enabled)
+ if(string_empty(value) || !parseCurve(value))
{
- m_set.insert(node);
+ m_controlPoints.allocate(0);
+ m_knots.allocate(0);
+ m_weights.allocate(0);
+ m_renderCurve.m_vertices.clear();
}
}
- void erase(scene::Node* node)
+ typedef MemberCaller1<NURBSCurve, const char*>::Caller<NURBSCurve::curveChanged> CurveChangedCaller;
+};
+
+class CatmullRomSpline
+{
+public:
+ ControlPoints m_controlPoints;
+ RenderableCurve m_renderCurve;
+
+ bool parseCurve(const char* value)
{
- RADIANT_ASSERT(m_model == node, "func_error");
- m_model = 0;
- if(m_enabled)
+ StringTokeniser tokeniser(value, " ");
+
+ std::size_t size;
+ if(!string_parse_size(tokeniser.getToken(), size))
{
- m_set.erase(node);
+ return false;
}
+
+ if(size < 3)
+ {
+ return false;
+ }
+ const int spline_degree = 3;
+
+ m_controlPoints.allocate(size);
+
+ if(!string_equal(tokeniser.getToken(), "("))
+ {
+ return false;
+ }
+ for(ControlPoints::iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
+ {
+ if(!string_parse_float(tokeniser.getToken(), (*i).x())
+ || !string_parse_float(tokeniser.getToken(), (*i).y())
+ || !string_parse_float(tokeniser.getToken(), (*i).z()))
+ {
+ return false;
+ }
+ }
+ if(!string_equal(tokeniser.getToken(), ")"))
+ {
+ return false;
+ }
+
+ const std::size_t numSegments = 64;
+ m_renderCurve.m_vertices.resize(numSegments + 1);
+ m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPoints[0]);
+ for(std::size_t i = 1; i < numSegments; ++i)
+ {
+ m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPoints, (1.0 / double(numSegments)) * double(i)));
+ }
+ m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPoints[m_controlPoints.size() - 1]);
+
+ return true;
}
- void traverse(Walker& walker)
+
+ void curveChanged(const char* value)
{
- m_set.traverse(walker);
+ if(string_empty(value) || !parseCurve(value))
+ {
+ m_controlPoints.allocate(0);
+ m_renderCurve.m_vertices.clear();
+ }
}
+ typedef MemberCaller1<CatmullRomSpline, const char*>::Caller<CatmullRomSpline::curveChanged> CurveChangedCaller;
};
-
class FuncStatic : public Editable
{
EntityKeyValues m_entity;
@@ -179,9 +303,8 @@
TraversableSet m_traverse;
FuncStaticOrigin m_funcStaticOrigin;
MatrixTransform m_transform;
- FuncStaticModelNode m_modelNode;
- Model m_model;
+ SingletonModel m_model;
Origin m_origin;
Angle m_angle;
Rotation m_rotation;
@@ -190,14 +313,21 @@
NamedEntity m_named;
NameKeys m_nameKeys;
+ NURBSCurve m_curveNURBS;
+ CatmullRomSpline m_curveCatmullRom;
+
Closure m_transformChanged;
string_t m_name;
string_t m_modelKey;
bool m_isModel;
+ scene::Node* m_node;
+
void construct(scene::Node* node)
{
+ m_node = node;
+
node->m_edit = this;
node->m_transform = &m_transform;
node->m_traverse = &m_traverse;
@@ -212,16 +342,50 @@
m_keyObservers.insert("angle", Angle::AngleChangedCaller(m_angle));
m_keyObservers.insert("rotation", Rotation::RotationChangedCaller(m_rotation));
m_keyObservers.insert("name", NameChangedCaller(*this));
+ m_keyObservers.insert("curve_Nurbs", NURBSCurve::CurveChangedCaller(m_curveNURBS));
+ m_keyObservers.insert("curve_CatmullRomSpline", CatmullRomSpline::CurveChangedCaller(m_curveCatmullRom));
+ m_isModel = false;
+ m_nameKeys.setKeyIsName(keyIsNameDoom3FuncStatic);
+ attachTraverse();
+
m_entity.attach(m_keyObservers);
-
- m_isModel = false;
}
void destroy()
{
m_entity.detach(m_keyObservers);
+
+ if(isModel())
+ {
+ detachModel();
+ }
+ else
+ {
+ detachTraverse();
+ }
}
+ void attachModel()
+ {
+ m_node->m_traverse = &m_model.getTraversable();
+ m_model.attach(&m_funcStaticOrigin);
+ }
+ void detachModel()
+ {
+ m_node->m_traverse = 0;
+ m_model.detach(&m_funcStaticOrigin);
+ }
+ void attachTraverse()
+ {
+ m_node->m_traverse = &m_traverse;
+ m_traverse.attach(&m_funcStaticOrigin);
+ }
+ void detachTraverse()
+ {
+ m_node->m_traverse = 0;
+ m_traverse.detach(&m_funcStaticOrigin);
+ }
+
bool isModel()
{
return m_isModel;
@@ -229,14 +393,19 @@
void setIsModel(bool newValue)
{
- m_modelNode.setEnabled(newValue);
if(newValue && !m_isModel)
{
+ detachTraverse();
+ attachModel();
+
m_nameKeys.setKeyIsName(Static<KeyIsName>::instance().m_keyIsName);
m_model.modelChanged(m_modelKey.c_str());
}
else if(!newValue && m_isModel)
{
+ detachModel();
+ attachTraverse();
+
m_nameKeys.setKeyIsName(keyIsNameDoom3FuncStatic);
}
m_isModel = newValue;
@@ -286,15 +455,16 @@
void originChanged()
{
updateTransform();
- m_funcStaticOrigin.originChanged();
+ if(!isModel())
+ {
+ m_funcStaticOrigin.originChanged();
+ }
}
typedef MemberCaller<FuncStatic>::Caller<&FuncStatic::originChanged> OriginChangedCaller;
public:
FuncStatic(EntityClass* eclass, scene::Node* node, const Closure& transformChanged) :
m_entity(eclass),
- m_modelNode(m_traverse),
- m_model(m_modelNode, UpdateTransformCaller(*this)),
m_origin(OriginChangedCaller(*this)),
m_angle(UpdateTransformCaller(*this)),
m_rotation(UpdateTransformCaller(*this)),
@@ -308,8 +478,6 @@
}
FuncStatic(const FuncStatic& other, scene::Node* node, const Closure& transformChanged) :
m_entity(other.m_entity),
- m_modelNode(m_traverse),
- m_model(m_modelNode, UpdateTransformCaller(*this)),
m_origin(OriginChangedCaller(*this)),
m_angle(UpdateTransformCaller(*this)),
m_rotation(UpdateTransformCaller(*this)),
@@ -371,6 +539,16 @@
void render(IRenderer* renderer, const VolumeTest& volume, const Matrix4& local2world) const
{
renderer->SetState(m_entity.eclass().m_state_wire, IRenderer::eWireframeOnly);
+ renderer->SetState(m_entity.eclass().m_state_wire, IRenderer::eFullMaterials);
+
+ if(!m_curveNURBS.m_renderCurve.m_vertices.empty())
+ {
+ renderer->Add(&m_curveNURBS.m_renderCurve, local2world);
+ }
+ if(!m_curveCatmullRom.m_renderCurve.m_vertices.empty())
+ {
+ renderer->Add(&m_curveCatmullRom.m_renderCurve, local2world);
+ }
}
// edit
Modified: GtkRadiant/trunk/plugins/entity/targetable.cpp
===================================================================
--- GtkRadiant/trunk/plugins/entity/targetable.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/targetable.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -1,9 +1,6 @@
#include "targetable.h"
-#include <map>
-
-
typedef std::map<string_t, targetables_t> targetnames_t;
const char* g_targetable_nameKey = "targetname";
Modified: GtkRadiant/trunk/plugins/entity/targetable.h
===================================================================
--- GtkRadiant/trunk/plugins/entity/targetable.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/entity/targetable.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -3,6 +3,7 @@
#define _INCLUDE_TARGETABLE_H_
#include <set>
+#include <map>
#include "cullable.h"
#include "renderable.h"
@@ -13,6 +14,7 @@
#include "selectionlib.h"
#include "entitylib.h"
#include "eclasslib.h"
+#include "stringio.h"
class Targetable
{
@@ -105,7 +107,8 @@
public:
TargetingEntity()
: m_targets(getTargetables(""))
- {}
+ {
+ }
void targetChanged(const char* target)
{
m_targets = getTargetables(target);
@@ -117,19 +120,25 @@
iterator begin() const
{
if(m_targets == 0)
+ {
return iterator();
+ }
return m_targets->begin();
}
iterator end() const
{
if(m_targets == 0)
+ {
return iterator();
+ }
return m_targets->end();
}
size_t size() const
{
if(m_targets == 0)
+ {
return 0;
+ }
return m_targets->size();
}
bool empty() const
@@ -139,11 +148,60 @@
};
+
+typedef std::map<std::size_t, TargetingEntity> TargetingEntities;
+
+class TargetKeys : public EntityKeyValues::Observer
+{
+ TargetingEntities m_targetingEntities;
+
+ bool readTargetKey(const char* key, std::size_t& index)
+ {
+ if(string_equal_n(key, "target", 6))
+ {
+ index = 0;
+ if(string_empty(key + 6) || string_parse_size(key + 6, index))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+public:
+ void insert(const char* key, EntityKeyValues::Value& value)
+ {
+ std::size_t index;
+ if(readTargetKey(key, index))
+ {
+ TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index, TargetingEntity())).first;
+ value.attach(TargetingEntity::TargetChangedCaller((*i).second));
+ }
+ }
+ void erase(const char* key, EntityKeyValues::Value& value)
+ {
+ std::size_t index;
+ if(readTargetKey(key, index))
+ {
+ TargetingEntities::iterator i = m_targetingEntities.find(index);
+ value.detach(TargetingEntity::TargetChangedCaller((*i).second));
+ m_targetingEntities.erase(i);
+ }
+ }
+ const TargetingEntities& get() const
+ {
+ return m_targetingEntities;
+ }
+};
+
+
+
class RenderableTargetingEntity
{
TargetingEntity& m_targets;
mutable RenderablePointVector m_target_lines;
public:
+ static Shader* m_state;
+
RenderableTargetingEntity(TargetingEntity& targets)
: m_targets(targets), m_target_lines(GL_LINES)
{
@@ -172,10 +230,50 @@
renderer->Add(&m_target_lines, g_matrix4_identity);
}
}
+};
+class RenderableTargetingEntities
+{
+ const TargetingEntities& m_targets;
+ mutable RenderablePointVector m_target_lines;
+public:
static Shader* m_state;
+
+ RenderableTargetingEntities(const TargetingEntities& targets)
+ : m_targets(targets), m_target_lines(GL_LINES)
+ {
+ }
+ void compile(const VolumeTest& volume, const Vector3& world_position) const
+ {
+ m_target_lines.clear();
+
+ for(TargetingEntities::const_iterator i = m_targets.begin(); i != m_targets.end(); ++i)
+ {
+ const TargetingEntity& targets = (*i).second;
+ for(TargetingEntity::iterator j = targets.begin(); j != targets.end(); ++j)
+ {
+ Vector3 start(world_position);
+ Vector3 end((*j)->world_position());
+ if(volume.TestLine(segment_for_startend(start, end)))
+ {
+ m_target_lines.push_back(PointVertex(reinterpret_cast<const vertex3f_t&>(start)));
+ m_target_lines.push_back(PointVertex(reinterpret_cast<const vertex3f_t&>(end)));
+ }
+ }
+ }
+ }
+ void Render(IRenderer* renderer, const VolumeTest& volume, const Vector3& world_position) const
+ {
+ if(!m_targets.empty())
+ {
+ compile(volume, world_position);
+
+ renderer->Add(&m_target_lines, g_matrix4_identity);
+ }
+ }
};
+
class TargetableInstance :
public BaseSelectableInstance,
public Targetable,
@@ -183,40 +281,34 @@
{
mutable vertex3f_t m_position;
EntityKeyValues& m_entity;
- TargetingEntity m_targeting;
+ TargetKeys m_targeting;
TargetedEntity m_targeted;
- RenderableTargetingEntity m_renderable;
+ RenderableTargetingEntities m_renderable;
public:
TargetableInstance(const scene::Path& path, scene::Instance* parent, EntityKeyValues& entity)
- : BaseSelectableInstance(path, parent), m_entity(entity), m_renderable(m_targeting), m_targeted(*static_cast<Targetable*>(this))
+ : BaseSelectableInstance(path, parent), m_entity(entity), m_renderable(m_targeting.get()), m_targeted(*static_cast<Targetable*>(this))
{
m_entity.attach(*this);
+ m_entity.attach(m_targeting);
}
~TargetableInstance()
{
+ m_entity.detach(m_targeting);
m_entity.detach(*this);
}
void insert(const char* key, EntityKeyValues::Value& value)
{
- if(string_equal(key, "target"))
+ if(string_equal(key, g_targetable_nameKey))
{
- value.attach(TargetingEntity::TargetChangedCaller(m_targeting));
- }
- else if(string_equal(key, g_targetable_nameKey))
- {
value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
}
}
void erase(const char* key, EntityKeyValues::Value& value)
{
- if(string_equal(key, "target"))
+ if(string_equal(key, g_targetable_nameKey))
{
- value.detach(TargetingEntity::TargetChangedCaller(m_targeting));
- }
- else if(string_equal(key, g_targetable_nameKey))
- {
value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
}
}
Modified: GtkRadiant/trunk/plugins/md3model/md5.cpp
===================================================================
--- GtkRadiant/trunk/plugins/md3model/md5.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/plugins/md3model/md5.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -106,9 +106,19 @@
typedef auto_array<MD5Weight> MD5Weights;
+typedef float MD5Component;
+typedef auto_array<MD5Component> MD5Components;
-bool MD5Model_parse(Model& model, Tokeniser* tokeniser)
+class MD5Frame
{
+public:
+ MD5Components m_components;
+};
+
+typedef auto_array<MD5Weight> MD5Weights;
+
+bool MD5_parseVersion(Tokeniser* tokeniser)
+{
{
const char* versionKey = tokeniser->getToken();
if(versionKey == 0 || !string_equal(versionKey, "MD5Version"))
@@ -125,6 +135,13 @@
return false;
}
}
+
+ return true;
+}
+
+bool MD5Anim_parse(Tokeniser* tokeniser)
+{
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVersion(tokeniser));
tokeniser->nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "commandline"));
@@ -132,11 +149,117 @@
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, commandline));
tokeniser->nextLine();
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numFrames"));
+ std::size_t numFrames;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numFrames));
+ tokeniser->nextLine();
+
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numJoints"));
std::size_t numJoints;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numJoints));
tokeniser->nextLine();
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "frameRate"));
+ std::size_t frameRate;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, frameRate));
+ tokeniser->nextLine();
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numAnimatedComponents"));
+ std::size_t numAnimatedComponents;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numAnimatedComponents));
+ tokeniser->nextLine();
+
+ // parse heirarchy
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "hierarchy"));
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
+ tokeniser->nextLine();
+
+ for(std::size_t i = 0; i < numJoints; ++i)
+ {
+ const char* name;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, name));
+ int parent;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseInteger(tokeniser, parent));
+ std::size_t flags;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, flags));
+ std::size_t index;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, index));
+ tokeniser->nextLine();
+ }
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
+ tokeniser->nextLine();
+
+ // parse bounds
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "bounds"));
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
+ tokeniser->nextLine();
+
+ for(std::size_t i = 0; i < numFrames; ++i)
+ {
+ Vector3 mins;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, mins));
+ Vector3 maxs;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, maxs));
+ tokeniser->nextLine();
+ }
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
+ tokeniser->nextLine();
+
+ // parse baseframe
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "baseframe"));
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
+ tokeniser->nextLine();
+
+ for(std::size_t i = 0; i < numJoints; ++i)
+ {
+ Vector3 position;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, position));
+ Vector3 rotation;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, rotation));
+ tokeniser->nextLine();
+ }
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
+ tokeniser->nextLine();
+
+ // parse frames
+ for(std::size_t i = 0; i < numFrames; ++i)
+ {
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "frame"));
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
+ tokeniser->nextLine();
+
+ for(std::size_t i = 0; i < numAnimatedComponents; ++i)
+ {
+ float component;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, component));
+ tokeniser->nextLine();
+ }
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
+ tokeniser->nextLine();
+ }
+
+ return true;
+}
+
+bool MD5Model_parse(Model& model, Tokeniser* tokeniser)
+{
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseVersion(tokeniser));
+ tokeniser->nextLine();
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "commandline"));
+ const char* commandline;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, commandline));
+ tokeniser->nextLine();
+
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numJoints"));
+ std::size_t numJoints;
+ MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numJoints));
+ tokeniser->nextLine();
+
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numMeshes"));
std::size_t numMeshes;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numMeshes));
Modified: GtkRadiant/trunk/radiant/brush.h
===================================================================
--- GtkRadiant/trunk/radiant/brush.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/brush.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -67,8 +67,8 @@
void SceneChangeNotify();
-//#define BRUSH_CONNECTIVITY_DEBUG
-//#define BRUSH_DEGENERATE_DEBUG
+#define BRUSH_CONNECTIVITY_DEBUG 0
+#define BRUSH_DEGENERATE_DEBUG 0
inline void print_vector3(const Vector3& v)
{
@@ -1067,7 +1067,7 @@
RADIANT_ASSERT(index < (unsigned int)numpoints, "update_move_planepts_vertex: invalid index");
const int opposite = Winding_Opposite(winding(), index);
- const int adjacent = (opposite+numpoints-1) % numpoints;
+ const int adjacent = Winding_wrap(winding(), opposite+numpoints-1);
planePoints[0] = winding()[opposite].vertex;
planePoints[1] = winding()[index].vertex;
planePoints[2] = winding()[adjacent].vertex;
@@ -1077,19 +1077,26 @@
void snapto(float snap)
{
undo_save();
+#if 0
RADIANT_ASSERT(plane3_valid(m_plane.plane3()), "invalid plane before snap to grid");
-#if 0
planepts_snap(m_plane.planePoints(), snap);
+ RADIANT_ASSERT(plane3_valid(m_plane.plane3()), "invalid plane after snap to grid");
#else
- PlanePoints planePoints;
- update_move_planepts_vertex(0, planePoints);
- vector3_snap(planePoints[0], snap);
- vector3_snap(planePoints[1], snap);
- vector3_snap(planePoints[2], snap);
- assign_planepts(planePoints);
+ if(contributes())
+ {
+ PlanePoints planePoints;
+ update_move_planepts_vertex(0, planePoints);
+ vector3_snap(planePoints[0], snap);
+ vector3_snap(planePoints[1], snap);
+ vector3_snap(planePoints[2], snap);
+ assign_planepts(planePoints);
+ }
#endif
m_plane.MakePlane();
- RADIANT_ASSERT(plane3_valid(m_plane.plane3()), "invalid plane after snap to grid");
+ if(!plane3_valid(m_plane.plane3()))
+ {
+ globalErrorStream() << "WARNING: invalid plane after snap to grid";
+ }
m_observer->planeChanged();
}
@@ -2919,12 +2926,25 @@
(*i)->vertex_clear();
}
+ inline bool plane3_inside(const Plane3& self, const Plane3& other) const
+ {
+ if(vector3_equal_epsilon(self.normal(), other.normal(), 0.001))
+ {
+ return self.dist() < other.dist();
+ }
+ return true;
+ }
+
bool plane_unique(unsigned int index) const
{
// duplicate plane
- for(unsigned int i = 0; i < index; ++i)
- if(plane3_equal(m_faces[index]->plane3(), m_faces[i]->plane3()))
+ for(unsigned int i = 0; i < m_faces.size(); ++i)
+ {
+ if(index != i && !plane3_inside(m_faces[index]->plane3(), m_faces[i]->plane3()))
+ {
return false;
+ }
+ }
return true;
}
@@ -2944,7 +2964,7 @@
std::size_t next = Winding_next(w, static_cast<unsigned int>(index));
if(Edge_isDegenerate(w[index].vertex, w[next].vertex))
{
-#if defined(BRUSH_DEGENERATE_DEBUG)
+#if BRUSH_DEGENERATE_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate edge adjacent to " << w[index].adjacent << "\n";
#endif
winding_t& other = m_faces[w[index].adjacent]->winding();
@@ -2972,7 +2992,7 @@
if(degen.numpoints == 2)
{
-#if defined(BRUSH_DEGENERATE_DEBUG)
+#if BRUSH_DEGENERATE_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate winding adjacent to " << degen[0].adjacent << ", " << degen[1].adjacent << "\n";
#endif
// this is an "edge" face, where the plane touches the edge of the brush
@@ -2981,7 +3001,7 @@
unsigned int index = Winding_FindAdjacent(w, i);
if(index != MAX_POINTS_ON_WINDING)
{
-#if defined(BRUSH_DEGENERATE_DEBUG)
+#if BRUSH_DEGENERATE_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << degen[0].adjacent << ": remapping adjacent " << w[index].adjacent << " to " << degen[1].adjacent << "\n";
#endif
w[index].adjacent = degen[1].adjacent;
@@ -2993,7 +3013,7 @@
unsigned int index = Winding_FindAdjacent(w, i);
if(index != MAX_POINTS_ON_WINDING)
{
-#if defined(BRUSH_DEGENERATE_DEBUG)
+#if BRUSH_DEGENERATE_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << degen[1].adjacent << ": remapping adjacent " << w[index].adjacent << " to " << degen[0].adjacent << "\n";
#endif
w[index].adjacent = degen[0].adjacent;
@@ -3018,7 +3038,7 @@
std::size_t next = Winding_next(w, j);
if(w[j].adjacent == w[next].adjacent)
{
-#if defined(BRUSH_DEGENERATE_DEBUG)
+#if BRUSH_DEGENERATE_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << i << ": removed duplicate edge adjacent to face " << w[j].adjacent << "\n";
#endif
w.erase(w.begin() + next);
@@ -3042,14 +3062,14 @@
winding_t& w = m_faces[i]->winding();
for(winding_t::iterator j = w.begin(); j != w.end();)
{
-#if defined(BRUSH_CONNECTIVITY_DEBUG)
+#if BRUSH_CONNECTIVITY_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << i << ": adjacent to face " << (*j).adjacent << "\n";
#endif
// remove unidirectional graph edges
if((*j).adjacent == c_brush_maxFaces
|| Winding_FindAdjacent(m_faces[(*j).adjacent]->winding(), i) == MAX_POINTS_ON_WINDING)
{
-#if defined(BRUSH_CONNECTIVITY_DEBUG)
+#if BRUSH_CONNECTIVITY_DEBUG
globalOutputStream() << "Brush::buildWindings: face " << i << ": removing unidirectional connectivity graph edge adjacent to face " << (*j).adjacent << "\n";
#endif
w.erase(j);
Modified: GtkRadiant/trunk/radiant/eclass_doom3.cpp
===================================================================
--- GtkRadiant/trunk/radiant/eclass_doom3.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/eclass_doom3.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -91,6 +91,8 @@
bool m_resolved;
string_t m_mesh;
string_t m_parent;
+ typedef std::map<string_t, string_t> Anims;
+ Anims m_anims;
Model() : m_resolved(false)
{
}
@@ -181,8 +183,10 @@
}
else if(string_equal(parameter, "anim"))
{
- const char* animName = tokeniser->getToken();
+ string_t animName(tokeniser->getToken());
const char* animFile = tokeniser->getToken();
+ model.m_anims.insert(Model::Anims::value_type(animName, animFile));
+
const char* token = tokeniser->getToken();
while(string_equal(token, ","))
@@ -228,6 +232,8 @@
RADIANT_ASSERT(string_equal(token, "{"), "error parsing entity definition");
tokeniser->nextLine();
+ StringOutputStream usage(256);
+
for(;;)
{
const char* key = tokeniser->getToken();
@@ -244,7 +250,7 @@
else if(string_equal(key, "editor_color"))
{
entityClass->colorSpecified = true;
- bool success = string_read_vector(tokeniser->getToken(), entityClass->color);
+ bool success = string_parse_vector(tokeniser->getToken(), entityClass->color);
RADIANT_ASSERT(success, "editor_color: parse error");
}
else if(string_equal(key, "editor_ragdoll"))
@@ -258,7 +264,7 @@
if(!string_equal(value, "?"))
{
entityClass->fixedsize = true;
- bool success = string_read_vector(value, entityClass->mins);
+ bool success = string_parse_vector(value, entityClass->mins);
RADIANT_ASSERT(success, "editor_mins: parse error");
}
}
@@ -269,44 +275,49 @@
if(!string_equal(value, "?"))
{
entityClass->fixedsize = true;
- bool success = string_read_vector(value, entityClass->maxs);
+ bool success = string_parse_vector(value, entityClass->maxs);
RADIANT_ASSERT(success, "editor_maxs: parse error");
}
}
else if(string_equal(key, "editor_usage"))
{
const char* value = tokeniser->getToken();
- entityClass->m_comments = value;
+ usage << value;
}
+ else if(string_equal_n(key, "editor_usage", 12))
+ {
+ const char* value = tokeniser->getToken();
+ usage << "\n" << value;
+ }
else if(string_equal_n(key, "editor_var ", 11))
{
entityClass->m_attributes.push_back(EntityClassAttribute("string", key + 11, key + 11));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal_n(key, "editor_snd ", 11))
{
entityClass->m_attributes.push_back(EntityClassAttribute("sound", key + 11, key + 11));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal_n(key, "editor_bool ", 12))
{
entityClass->m_attributes.push_back(EntityClassAttribute("boolean", key + 12, key + 12));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal_n(key, "editor_model ", 13))
{
entityClass->m_attributes.push_back(EntityClassAttribute("model", key + 13, key + 13));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal_n(key, "editor_color ", 13))
{
entityClass->m_attributes.push_back(EntityClassAttribute("color", key + 13, key + 13));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal_n(key, "editor_material ", 16))
{
entityClass->m_attributes.push_back(EntityClassAttribute("shader", key + 16, key + 16));
- const char* value = tokeniser->getToken();
+ entityClass->m_attributes.back().m_description = tokeniser->getToken();
}
else if(string_equal(key, "inherit"))
{
@@ -321,6 +332,15 @@
tokeniser->nextLine();
}
+ usage << "\n";
+
+ for(EntityClassAttributes::iterator i = entityClass->m_attributes.begin(); i != entityClass->m_attributes.end(); ++i)
+ {
+ usage << "\n" << (*i).m_name.c_str() << ": " << (*i).m_description.c_str();
+ }
+
+ entityClass->m_comments = usage.c_str();
+
EntityClassDoom3_insertUnique(entityClass);
}
Modified: GtkRadiant/trunk/radiant/entityinspector.cpp
===================================================================
--- GtkRadiant/trunk/radiant/entityinspector.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/entityinspector.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -111,6 +111,60 @@
virtual void release() = 0;
};
+class BooleanAttribute : public EntityAttribute
+{
+public:
+ string_t m_key;
+ GtkWidget* m_check;
+
+ static gboolean toggled(GtkWidget *widget, BooleanAttribute* self)
+ {
+ self->apply();
+ return FALSE;
+ }
+public:
+ BooleanAttribute(const char* key, const char* name) :
+ m_key(key),
+ m_check(0)
+ {
+ GtkWidget* check = gtk_check_button_new();
+ gtk_widget_show(check);
+
+ m_check = check;
+
+ guint handler = g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggled), this);
+ g_object_set_data(G_OBJECT(check), "handler", gint_to_pointer(handler));
+
+ update();
+
+ EntityInspector_appendAttribute(name, check);
+ }
+ void release()
+ {
+ delete this;
+ }
+ void apply()
+ {
+ Scene_EntitySetKeyValue_Selected_Undoable(m_key.c_str(), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_check)) ? "1" : "0");
+ }
+ typedef MemberCaller<BooleanAttribute>::Caller<&BooleanAttribute::apply> ApplyCaller;
+
+ void update()
+ {
+ KeyValues::const_iterator i = display_entity.find(m_key.c_str());
+ if(i != display_entity.end())
+ {
+ toggle_button_set_active_no_signal(m_check, atoi((*i).second.c_str()) != 0);
+ }
+ else
+ {
+ toggle_button_set_active_no_signal(m_check, false);
+ }
+ }
+ typedef MemberCaller<BooleanAttribute>::Caller<&BooleanAttribute::update> UpdateCaller;
+};
+
+
class StringAttribute : public EntityAttribute
{
public:
@@ -618,11 +672,14 @@
{
if(string_equal((*i).m_type.c_str(), "string")
|| string_equal((*i).m_type.c_str(), "shader")
- || string_equal((*i).m_type.c_str(), "boolean")
|| string_equal((*i).m_type.c_str(), "color"))
{
g_entityAttributes.push_back(new StringAttribute((*i).m_key.c_str(), (*i).m_name.c_str()));
}
+ else if(string_equal((*i).m_type.c_str(), "boolean"))
+ {
+ g_entityAttributes.push_back(new BooleanAttribute((*i).m_key.c_str(), (*i).m_name.c_str()));
+ }
else if(string_equal((*i).m_type.c_str(), "angle"))
{
g_entityAttributes.push_back(new AngleAttribute((*i).m_key.c_str(), (*i).m_name.c_str()));
Modified: GtkRadiant/trunk/radiant/mainframe.cpp
===================================================================
--- GtkRadiant/trunk/radiant/mainframe.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/mainframe.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -711,14 +711,34 @@
}
typedef FreeCaller1<const BoolImportClosure&, ShowWorkzoneExport> ShowWorkzoneExportCaller;
-ToggleItem g_show_names = ShowNamesExportCaller();
-ToggleItem g_show_angles = ShowAnglesExportCaller();
-ToggleItem g_show_blocks = ShowBlocksExportCaller();
-ToggleItem g_show_coordinates = ShowCoordinatesExportCaller();
-ToggleItem g_show_outline = ShowOutlineExportCaller();
-ToggleItem g_show_axes = ShowAxesExportCaller();
-ToggleItem g_show_workzone = ShowWorkzoneExportCaller();
+ShowNamesExportCaller g_show_names_caller;
+BoolExportClosure g_show_names_closure(g_show_names_caller);
+ToggleItem g_show_names(g_show_names_closure);
+ShowAnglesExportCaller g_show_angles_caller;
+BoolExportClosure g_show_angles_closure(g_show_angles_caller);
+ToggleItem g_show_angles(g_show_angles_closure);
+
+ShowBlocksExportCaller g_show_blocks_caller;
+BoolExportClosure g_show_blocks_closure(g_show_blocks_caller);
+ToggleItem g_show_blocks(g_show_blocks_closure);
+
+ShowCoordinatesExportCaller g_show_coordinates_caller;
+BoolExportClosure g_show_coordinates_closure(g_show_coordinates_caller);
+ToggleItem g_show_coordinates(g_show_coordinates_closure);
+
+ShowOutlineExportCaller g_show_outline_caller;
+BoolExportClosure g_show_outline_closure(g_show_outline_caller);
+ToggleItem g_show_outline(g_show_outline_closure);
+
+ShowAxesExportCaller g_show_axes_caller;
+BoolExportClosure g_show_axes_closure(g_show_axes_caller);
+ToggleItem g_show_axes(g_show_axes_closure);
+
+ShowWorkzoneExportCaller g_show_workzone_caller;
+BoolExportClosure g_show_workzone_closure(g_show_workzone_caller);
+ToggleItem g_show_workzone(g_show_workzone_closure);
+
void XYShow_registerCommands()
{
global_toggles_insert("ShowAngles", ShowAnglesToggleCaller(), ToggleItem::AddClosureCaller(g_show_angles));
@@ -1175,10 +1195,18 @@
}
};
-ToggleItem g_edgeMode_button = FreeCaller1<const BoolImportClosure&, BoolFunctionExport<EdgeMode>::apply>();
-ToggleItem g_vertexMode_button = FreeCaller1<const BoolImportClosure&, BoolFunctionExport<VertexMode>::apply>();
-ToggleItem g_faceMode_button = FreeCaller1<const BoolImportClosure&, BoolFunctionExport<FaceMode>::apply>();
+FreeCaller1<const BoolImportClosure&, BoolFunctionExport<EdgeMode>::apply> g_edgeMode_button_caller;
+BoolExportClosure g_edgeMode_button_closure(g_edgeMode_button_caller);
+ToggleItem g_edgeMode_button(g_edgeMode_button_closure);
+FreeCaller1<const BoolImportClosure&, BoolFunctionExport<VertexMode>::apply> g_vertexMode_button_caller;
+BoolExportClosure g_vertexMode_button_closure(g_vertexMode_button_caller);
+ToggleItem g_vertexMode_button(g_vertexMode_button_closure);
+
+FreeCaller1<const BoolImportClosure&, BoolFunctionExport<FaceMode>::apply> g_faceMode_button_caller;
+BoolExportClosure g_faceMode_button_closure(g_faceMode_button_caller);
+ToggleItem g_faceMode_button(g_faceMode_button_closure);
+
void ComponentModeChanged()
{
g_edgeMode_button.update();
@@ -1458,12 +1486,26 @@
importClosure(GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip);
}
-ToggleItem g_translatemode_button = FreeCaller1<const BoolImportClosure&, TranslateToolExport>();
-ToggleItem g_rotatemode_button = FreeCaller1<const BoolImportClosure&, RotateToolExport>();
-ToggleItem g_scalemode_button = FreeCaller1<const BoolImportClosure&, ScaleToolExport>();
-ToggleItem g_dragmode_button = FreeCaller1<const BoolImportClosure&, DragToolExport>();
-ToggleItem g_clipper_button = FreeCaller1<const BoolImportClosure&, ClipperToolExport>();
+FreeCaller1<const BoolImportClosure&, TranslateToolExport> g_translatemode_button_caller;
+BoolExportClosure g_translatemode_button_closure(g_translatemode_button_caller);
+ToggleItem g_translatemode_button(g_translatemode_button_closure);
+FreeCaller1<const BoolImportClosure&, RotateToolExport> g_rotatemode_button_caller;
+BoolExportClosure g_rotatemode_button_closure(g_rotatemode_button_caller);
+ToggleItem g_rotatemode_button(g_rotatemode_button_closure);
+
+FreeCaller1<const BoolImportClosure&, ScaleToolExport> g_scalemode_button_caller;
+BoolExportClosure g_scalemode_button_closure(g_scalemode_button_caller);
+ToggleItem g_scalemode_button(g_scalemode_button_closure);
+
+FreeCaller1<const BoolImportClosure&, DragToolExport> g_dragmode_button_caller;
+BoolExportClosure g_dragmode_button_closure(g_dragmode_button_caller);
+ToggleItem g_dragmode_button(g_dragmode_button_closure);
+
+FreeCaller1<const BoolImportClosure&, ClipperToolExport> g_clipper_button_caller;
+BoolExportClosure g_clipper_button_closure(g_clipper_button_caller);
+ToggleItem g_clipper_button(g_clipper_button_closure);
+
void ToolChanged()
{
g_translatemode_button.update();
@@ -3450,8 +3492,8 @@
global_commands_insert("ShowHidden", FreeCaller<Select_ShowAllHidden>(), Accelerator('H', (GdkModifierType)GDK_SHIFT_MASK));
global_commands_insert("HideSelected", FreeCaller<HideSelected>(), Accelerator('H'));
- global_toggles_insert("DragVertices", FreeCaller<SelectVertexMode>(), ToggleItem::AddClosureCaller(g_vertexMode_button), Accelerator('E'));
- global_toggles_insert("DragEdges", FreeCaller<SelectEdgeMode>(), ToggleItem::AddClosureCaller(g_edgeMode_button), Accelerator('V'));
+ global_toggles_insert("DragVertices", FreeCaller<SelectVertexMode>(), ToggleItem::AddClosureCaller(g_vertexMode_button), Accelerator('V'));
+ global_toggles_insert("DragEdges", FreeCaller<SelectEdgeMode>(), ToggleItem::AddClosureCaller(g_edgeMode_button), Accelerator('E'));
global_toggles_insert("DragFaces", FreeCaller<SelectFaceMode>(), ToggleItem::AddClosureCaller(g_faceMode_button), Accelerator('F'));
global_commands_insert("MirrorSelectionX", FreeCaller<Selection_Flipx>());
@@ -3469,8 +3511,8 @@
global_commands_insert("FindBrush", FreeCaller<DoFind>());
global_commands_insert("MapInfo", FreeCaller<DoMapInfo>(), Accelerator('M'));
- global_commands_insert("EntityColor", FreeCaller<Entity_setColour>(), Accelerator('K', (GdkModifierType)GDK_CONTROL_MASK));
- global_commands_insert("ConnectSelection", FreeCaller<ConnectEntities>(), Accelerator('K'));
+ global_commands_insert("EntityColor", FreeCaller<Entity_setColour>(), Accelerator('K'));
+ global_commands_insert("ConnectSelection", FreeCaller<ConnectEntities>(), Accelerator('K', (GdkModifierType)GDK_CONTROL_MASK));
global_toggles_insert("ToggleClipper", FreeCaller<ClipperMode>(), ToggleItem::AddClosureCaller(g_clipper_button), Accelerator('X'));
Modified: GtkRadiant/trunk/radiant/map.cpp
===================================================================
--- GtkRadiant/trunk/radiant/map.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/map.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -152,17 +152,24 @@
std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
RADIANT_ASSERT(result.second, "cannot attach name");
attachObserver(NameObserver::NameChangedCaller((*result.first).second));
- globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
+ //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
}
void detach(const NameClosure& setName, const NameClosureClosure& detachObserver)
{
Names::iterator i = m_names.find(setName);
RADIANT_ASSERT(i != m_names.end(), "cannot detach name");
- globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
+ //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
detachObserver(NameObserver::NameChangedCaller((*i).second));
m_names.erase(i);
}
+ void makeUnique(const char* name, const NameClosure& setName) const
+ {
+ char buffer[1024];
+ name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
+ setName(buffer);
+ }
+
void mergeNames(const BasicNamespace& other) const
{
typedef std::list<NameClosure> SetNameClosures;
@@ -502,7 +509,7 @@
if (entity)
{
Vector3 origin;
- string_read_vector(entity->valueforkey("origin"), origin);
+ string_parse_vector(entity->valueforkey("origin"), origin);
FocusViews(origin, string_read_float(entity->valueforkey("angle")));
}
else
@@ -2082,7 +2089,7 @@
entity_find walker(entity, path);
path.top()->m_traverse->traverse(walker);
}
- if(path.size())
+ if(path.size() && path.top()->m_traverse != 0)
{
brush_find walker(brush, path);
path.top()->m_traverse->traverse(walker);
@@ -2091,11 +2098,12 @@
void SelectBrush (int entitynum, int brushnum)
{
- scene::Path brushpath;
- Scene_FindEntityBrush(entitynum, brushnum, brushpath);
- if(brushpath.size())
+ scene::Path path;
+ Scene_FindEntityBrush(entitynum, brushnum, path);
+ if(path.size())
{
- scene::Instance& instance = *GlobalSceneGraph().find(brushpath);
+ scene::Instance& instance = *GlobalSceneGraph().find(path);
+ RADIANT_ASSERT(instance.selectable() != 0, "SelectBrush: object not selectable");
instance.selectable()->select(true);
g_pParentWnd->GetXYWnd()->PositionView(instance.aabb_world().origin);
}
Modified: GtkRadiant/trunk/radiant/referencecache.cpp
===================================================================
--- GtkRadiant/trunk/radiant/referencecache.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/referencecache.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -331,7 +331,7 @@
}
else
{
- if(string_not_empty(m_name.c_str()))
+ if(string_not_empty(m_type.c_str()))
{
globalErrorStream() << "Model type not supported: \"" << m_name.c_str() << "\"\n";
}
Modified: GtkRadiant/trunk/radiant/texwindow.cpp
===================================================================
--- GtkRadiant/trunk/radiant/texwindow.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/texwindow.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -870,10 +870,18 @@
}
typedef FreeCaller1<const BoolImportClosure&, TextureBrowser_showShaderlistOnly> TextureBrowserShowShaderlistOnlyExport;
-ToggleItem g_textureswindow_hideunused_item = TextureBrowserHideUnusedExport();
-ToggleItem g_textureswindow_showshaders_item = TextureBrowserShowShadersExport();
-ToggleItem g_textureswindow_showshaderlistonly_item = TextureBrowserShowShaderlistOnlyExport();
+TextureBrowserHideUnusedExport g_textureswindow_hideunused_item_caller;
+BoolExportClosure g_textureswindow_hideunused_item_closure(g_textureswindow_hideunused_item_caller);
+ToggleItem g_textureswindow_hideunused_item(g_textureswindow_hideunused_item_closure);
+TextureBrowserShowShadersExport g_textureswindow_showshaders_item_caller;
+BoolExportClosure g_textureswindow_showshaders_item_closure(g_textureswindow_showshaders_item_caller);
+ToggleItem g_textureswindow_showshaders_item(g_textureswindow_showshaders_item_closure);
+
+TextureBrowserShowShaderlistOnlyExport g_textureswindow_showshaderlistonly_item_caller;
+BoolExportClosure g_textureswindow_showshaderlistonly_item_closure(g_textureswindow_showshaderlistonly_item_caller);
+ToggleItem g_textureswindow_showshaderlistonly_item(g_textureswindow_showshaderlistonly_item_closure);
+
void TextureBrowser_SetHideUnused(TextureBrowser& textureBrowser, bool hideUnused)
{
if(hideUnused)
Modified: GtkRadiant/trunk/radiant/winding.cpp
===================================================================
--- GtkRadiant/trunk/radiant/winding.cpp 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/winding.cpp 2004-09-21 18:46:46 UTC (rev 4792)
@@ -278,7 +278,7 @@
unsigned int Winding_Opposite(const winding_t& w, const unsigned int index)
{
- return Winding_Opposite(w, index, (index+1) % w.numpoints);
+ return Winding_Opposite(w, index, Winding_next(w, index));
}
void Winding_Centroid(const winding_t& w, const Plane3& plane, Vector3& centroid)
Modified: GtkRadiant/trunk/radiant/winding.h
===================================================================
--- GtkRadiant/trunk/radiant/winding.h 2004-09-16 18:14:45 UTC (rev 4791)
+++ GtkRadiant/trunk/radiant/winding.h 2004-09-21 18:46:46 UTC (rev 4792)
@@ -221,8 +221,15 @@
};
+inline unsigned int Winding_wrap(const winding_t& winding, unsigned int i)
+{
+ RADIANT_ASSERT(winding.numpoints != 0, "Winding_wrap: empty winding");
+ return i % winding.numpoints;
+}
+
inline unsigned int Winding_next(const winding_t& winding, unsigned int i)
{
+ RADIANT_ASSERT(winding.numpoints != 0, "Winding_next: empty winding");
return ++i % winding.numpoints;
}
More information about the Gtkradiant
mailing list