mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2025-01-10 03:51:18 +00:00
added string-pooling for shader variable names and entity keys
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@26 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
parent
24230bb3a8
commit
d584d94549
27 changed files with 159 additions and 111 deletions
|
@ -111,6 +111,8 @@ public:
|
||||||
virtual bool getShowNames() = 0;
|
virtual bool getShowNames() = 0;
|
||||||
virtual void setShowAngles(bool showAngles) = 0;
|
virtual void setShowAngles(bool showAngles) = 0;
|
||||||
virtual bool getShowAngles() = 0;
|
virtual bool getShowAngles() = 0;
|
||||||
|
|
||||||
|
virtual void printStatistics() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "modulesystem.h"
|
#include "modulesystem.h"
|
||||||
|
|
|
@ -320,6 +320,15 @@ inline hash_t string_hash_nocase(const char* string, hash_t previous = 0)
|
||||||
return hash_ub1_nocase(reinterpret_cast<const ub1*>(string), string_length(string), previous);
|
return hash_ub1_nocase(reinterpret_cast<const ub1*>(string), string_length(string), previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RawStringHash
|
||||||
|
{
|
||||||
|
typedef hash_t hash_type;
|
||||||
|
hash_type operator()(const char* string) const
|
||||||
|
{
|
||||||
|
return string_hash(string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct HashString
|
struct HashString
|
||||||
{
|
{
|
||||||
typedef hash_t hash_type;
|
typedef hash_t hash_type;
|
||||||
|
|
|
@ -166,11 +166,11 @@ namespace HashTableDetail
|
||||||
increment();
|
increment();
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
value_type& operator*()
|
value_type& operator*() const
|
||||||
{
|
{
|
||||||
return m_node->m_value;
|
return m_node->m_value;
|
||||||
}
|
}
|
||||||
value_type* operator->()
|
value_type* operator->() const
|
||||||
{
|
{
|
||||||
return &(operator*());
|
return &(operator*());
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
|
||||||
return ostream << convert.m_range;
|
return ostream << convert.m_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const char* p = convert.m_range.begin; p != convert.m_range.end;)
|
for(const char* p = convert.m_range.first; p != convert.m_range.last;)
|
||||||
{
|
{
|
||||||
if(!char_is_ascii(*p))
|
if(!char_is_ascii(*p))
|
||||||
{
|
{
|
||||||
|
@ -286,7 +286,7 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
|
||||||
return ostream << convert.m_range;
|
return ostream << convert.m_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const char* p = convert.m_range.begin; p != convert.m_range.end; ++p)
|
for(const char* p = convert.m_range.first; p != convert.m_range.last; ++p)
|
||||||
{
|
{
|
||||||
if(!char_is_ascii(*p))
|
if(!char_is_ascii(*p))
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
#include "math/vector.h"
|
#include "math/vector.h"
|
||||||
#include "math/aabb.h"
|
#include "math/aabb.h"
|
||||||
#include "undolib.h"
|
#include "undolib.h"
|
||||||
#include "string/string.h"
|
#include "string/pooledstring.h"
|
||||||
#include "generic/referencecounted.h"
|
#include "generic/referencecounted.h"
|
||||||
#include "scenelib.h"
|
#include "scenelib.h"
|
||||||
#include "container/container.h"
|
#include "container/container.h"
|
||||||
|
@ -421,14 +421,21 @@ public:
|
||||||
virtual void erase(const char* key, Value& value) = 0;
|
virtual void erase(const char* key, Value& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static StringPool& getPool()
|
||||||
|
{
|
||||||
|
return Static<StringPool, KeyContext>::instance();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
|
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
|
||||||
static Counter* m_counter;
|
static Counter* m_counter;
|
||||||
|
|
||||||
EntityClass* m_eclass;
|
EntityClass* m_eclass;
|
||||||
|
|
||||||
|
class KeyContext{};
|
||||||
|
typedef Static<StringPool, KeyContext> KeyPool;
|
||||||
|
typedef PooledString<KeyPool> Key;
|
||||||
typedef SmartPointer<KeyValue> KeyValuePtr;
|
typedef SmartPointer<KeyValue> KeyValuePtr;
|
||||||
typedef UnsortedMap<CopiedString, KeyValuePtr > KeyValues;
|
typedef UnsortedMap<Key, KeyValuePtr> KeyValues;
|
||||||
KeyValues m_keyValues;
|
KeyValues m_keyValues;
|
||||||
|
|
||||||
typedef UnsortedSet<Observer*> Observers;
|
typedef UnsortedSet<Observer*> Observers;
|
||||||
|
@ -504,7 +511,7 @@ private:
|
||||||
(*i).second->instanceDetach(m_undo.map());
|
(*i).second->instanceDetach(m_undo.map());
|
||||||
}
|
}
|
||||||
|
|
||||||
CopiedString key((*i).first);
|
Key key((*i).first);
|
||||||
KeyValuePtr value((*i).second);
|
KeyValuePtr value((*i).second);
|
||||||
m_keyValues.erase(i);
|
m_keyValues.erase(i);
|
||||||
notifyErase(key.c_str(), *value);
|
notifyErase(key.c_str(), *value);
|
||||||
|
|
|
@ -57,8 +57,8 @@ class GenericFileSystem
|
||||||
: m_path(path), m_depth(path_get_depth(c_str()))
|
: m_path(path), m_depth(path_get_depth(c_str()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Path(const char* start, const char* finish)
|
Path(StringRange range)
|
||||||
: m_path(start, finish), m_depth(path_get_depth(c_str()))
|
: m_path(range), m_depth(path_get_depth(c_str()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
bool operator<(const Path& other) const
|
bool operator<(const Path& other) const
|
||||||
|
@ -121,7 +121,7 @@ public:
|
||||||
const char* end = path_remove_directory(path.c_str());
|
const char* end = path_remove_directory(path.c_str());
|
||||||
while(end[0] != '\0')
|
while(end[0] != '\0')
|
||||||
{
|
{
|
||||||
Path dir(path.c_str(), end);
|
Path dir(StringRange(path.c_str(), end));
|
||||||
m_entries.insert(value_type(dir, Entry(0)));
|
m_entries.insert(value_type(dir, Entry(0)));
|
||||||
end = path_remove_directory(end);
|
end = path_remove_directory(end);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,36 +29,36 @@ template<typename Element>
|
||||||
struct ArrayRange
|
struct ArrayRange
|
||||||
{
|
{
|
||||||
typedef Element* Iterator;
|
typedef Element* Iterator;
|
||||||
ArrayRange(Iterator _begin, Iterator _end)
|
ArrayRange(Iterator first, Iterator last)
|
||||||
: begin(_begin), end(_end)
|
: first(first), last(last)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Iterator begin;
|
Iterator first;
|
||||||
Iterator end;
|
Iterator last;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Element>
|
template<typename Element>
|
||||||
inline ArrayRange<Element> makeArrayRange(Element* begin, Element* end)
|
inline ArrayRange<Element> makeArrayRange(Element* first, Element* last)
|
||||||
{
|
{
|
||||||
return ArrayRange<Element>(begin, end);
|
return ArrayRange<Element>(first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Element>
|
template<typename Element>
|
||||||
struct ArrayConstRange
|
struct ArrayConstRange
|
||||||
{
|
{
|
||||||
typedef const Element* Iterator;
|
typedef const Element* Iterator;
|
||||||
ArrayConstRange(Iterator _begin, Iterator _end)
|
ArrayConstRange(Iterator first, Iterator last)
|
||||||
: begin(_begin), end(_end)
|
: first(first), last(last)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Iterator begin;
|
Iterator first;
|
||||||
Iterator end;
|
Iterator last;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Element>
|
template<typename Element>
|
||||||
inline ArrayConstRange<Element> makeArrayRange(const Element* begin, const Element* end)
|
inline ArrayConstRange<Element> makeArrayRange(const Element* first, const Element* last)
|
||||||
{
|
{
|
||||||
return ArrayConstRange<Element>(begin, end);
|
return ArrayConstRange<Element>(first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
|
||||||
|
@ -69,4 +69,6 @@ inline ArrayConstRange<Element> makeArrayRange(const Element* begin, const Eleme
|
||||||
typedef ArrayConstRange<const char*> StringArrayRange;
|
typedef ArrayConstRange<const char*> StringArrayRange;
|
||||||
#define STRING_ARRAY_RANGE(array) (StringArrayRange(array, ARRAY_END(array)))
|
#define STRING_ARRAY_RANGE(array) (StringArrayRange(array, ARRAY_END(array)))
|
||||||
|
|
||||||
|
typedef ArrayRange<const char> StringRange;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,4 +45,6 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
|
||||||
#define STRING_CONSTANT(name, value) TYPE_CONSTANT(name, value, const char*)
|
#define STRING_CONSTANT(name, value) TYPE_CONSTANT(name, value, const char*)
|
||||||
#define INTEGER_CONSTANT(name, value) TYPE_CONSTANT(name, value, int)
|
#define INTEGER_CONSTANT(name, value) TYPE_CONSTANT(name, value, int)
|
||||||
|
|
||||||
|
STRING_CONSTANT(EmptyString, "");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,14 +27,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
class Null
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief A singleton which is statically initialised.
|
/// \brief A singleton which is statically initialised.
|
||||||
///
|
///
|
||||||
/// \param Type The singleton object type.
|
/// \param Type The singleton object type.
|
||||||
|
/// \param Type The type distinguishing this instance from others of the same type.
|
||||||
///
|
///
|
||||||
/// \dontinclude generic/static.cpp
|
/// \dontinclude generic/static.cpp
|
||||||
/// \skipline Static example
|
/// \skipline Static example
|
||||||
/// \until end example
|
/// \until end example
|
||||||
template<typename Type>
|
template<typename Type, typename Context = Null>
|
||||||
class Static
|
class Static
|
||||||
{
|
{
|
||||||
static Type m_instance;
|
static Type m_instance;
|
||||||
|
@ -45,19 +50,20 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, typename Context>
|
||||||
Type Static<Type>::m_instance;
|
Type Static<Type, Context>::m_instance;
|
||||||
|
|
||||||
|
|
||||||
/// \brief A singleton which is lazily initialised.
|
/// \brief A singleton which is lazily initialised.
|
||||||
/// The instance is constructed the first time it is referenced, and is never destroyed.
|
/// The instance is constructed the first time it is referenced, and is never destroyed.
|
||||||
///
|
///
|
||||||
/// \param Type The singleton object type.
|
/// \param Type The singleton object type.
|
||||||
|
/// \param Type The type distinguishing this instance from others of the same type.
|
||||||
///
|
///
|
||||||
/// \dontinclude generic/static.cpp
|
/// \dontinclude generic/static.cpp
|
||||||
/// \skipline LazyStatic example
|
/// \skipline LazyStatic example
|
||||||
/// \until end example
|
/// \until end example
|
||||||
template<typename Type>
|
template<typename Type, typename Context = Null>
|
||||||
class LazyStatic
|
class LazyStatic
|
||||||
{
|
{
|
||||||
static Type* m_instance; // this will be initialised to 0 by the CRT, according to the c++ standard
|
static Type* m_instance; // this will be initialised to 0 by the CRT, according to the c++ standard
|
||||||
|
@ -72,8 +78,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, typename Context>
|
||||||
Type* LazyStatic<Type>::m_instance;
|
Type* LazyStatic<Type, Context>::m_instance;
|
||||||
|
|
||||||
|
|
||||||
/// \brief A singleton which keeps a count of the number of times it is referenced.
|
/// \brief A singleton which keeps a count of the number of times it is referenced.
|
||||||
|
@ -82,7 +88,8 @@ Type* LazyStatic<Type>::m_instance;
|
||||||
/// Use with SmartStatic.
|
/// Use with SmartStatic.
|
||||||
///
|
///
|
||||||
/// \param Type The singleton object type.
|
/// \param Type The singleton object type.
|
||||||
template<typename Type>
|
/// \param Type The type distinguishing this instance from others of the same type.
|
||||||
|
template<typename Type, typename Context = Null>
|
||||||
class CountedStatic
|
class CountedStatic
|
||||||
{
|
{
|
||||||
static std::size_t m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
|
static std::size_t m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
|
||||||
|
@ -108,34 +115,35 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type, typename Context>
|
||||||
std::size_t CountedStatic<Type>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
|
std::size_t CountedStatic<Type, Context>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
|
||||||
template<typename Type>
|
template<typename Type, typename Context>
|
||||||
Type* CountedStatic<Type>::m_instance;
|
Type* CountedStatic<Type, Context>::m_instance;
|
||||||
|
|
||||||
/// \brief A reference to a CountedStatic.
|
/// \brief A reference to a CountedStatic.
|
||||||
/// Guarantees that CountedStatic<Type> will be constructed for the lifetime of this object.
|
/// Guarantees that CountedStatic<Type> will be constructed for the lifetime of this object.
|
||||||
///
|
///
|
||||||
/// \param Type The type parameter of the CountedStatic to reference.
|
/// \param Type The type parameter of the CountedStatic to reference.
|
||||||
|
/// \param Type The type distinguishing this instance from others of the same type.
|
||||||
///
|
///
|
||||||
/// \dontinclude generic/static.cpp
|
/// \dontinclude generic/static.cpp
|
||||||
/// \skipline SmartStatic example
|
/// \skipline SmartStatic example
|
||||||
/// \until end example
|
/// \until end example
|
||||||
template<typename Type>
|
template<typename Type, typename Context = Null>
|
||||||
class SmartStatic
|
class SmartStatic
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SmartStatic()
|
SmartStatic()
|
||||||
{
|
{
|
||||||
CountedStatic<Type>::capture();
|
CountedStatic<Type, Context>::capture();
|
||||||
}
|
}
|
||||||
~SmartStatic()
|
~SmartStatic()
|
||||||
{
|
{
|
||||||
CountedStatic<Type>::release();
|
CountedStatic<Type, Context>::release();
|
||||||
}
|
}
|
||||||
Type& instance()
|
Type& instance()
|
||||||
{
|
{
|
||||||
return CountedStatic<Type>::instance();
|
return CountedStatic<Type, Context>::instance();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,7 @@ RadioHBox RadioHBox_new(StringArrayRange names)
|
||||||
|
|
||||||
GSList* group = 0;
|
GSList* group = 0;
|
||||||
GtkRadioButton* radio = 0;
|
GtkRadioButton* radio = 0;
|
||||||
for(StringArrayRange::Iterator i = names.begin; i != names.end; ++i)
|
for(StringArrayRange::Iterator i = names.first; i != names.last; ++i)
|
||||||
{
|
{
|
||||||
radio = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(group, *i));
|
radio = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(group, *i));
|
||||||
gtk_widget_show(GTK_WIDGET(radio));
|
gtk_widget_show(GTK_WIDGET(radio));
|
||||||
|
|
|
@ -193,6 +193,12 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="string"
|
Name="string"
|
||||||
Filter="">
|
Filter="">
|
||||||
|
<File
|
||||||
|
RelativePath=".\string\pooledstring.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\string\pooledstring.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\string\string.cpp">
|
RelativePath=".\string\string.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
|
|
@ -302,13 +302,11 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef ArrayRange<const char> StringRange;
|
|
||||||
|
|
||||||
/// \brief Writes a \p range of characters to \p ostream.
|
/// \brief Writes a \p range of characters to \p ostream.
|
||||||
template<typename TextOutputStreamType>
|
template<typename TextOutputStreamType>
|
||||||
inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const StringRange& range)
|
inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const StringRange& range)
|
||||||
{
|
{
|
||||||
ostream.write(range.begin, range.end - range.begin);
|
ostream.write(range.first, range.last - range.first);
|
||||||
return ostream;
|
return ostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "memory/allocator.h"
|
#include "memory/allocator.h"
|
||||||
|
#include "generic/arrayrange.h"
|
||||||
|
|
||||||
/// \brief Returns true if \p string length is zero.
|
/// \brief Returns true if \p string length is zero.
|
||||||
/// O(1)
|
/// O(1)
|
||||||
|
@ -191,10 +192,10 @@ inline char* string_clone(const char* other, Allocator& allocator)
|
||||||
/// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
|
/// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
|
||||||
/// The returned buffer must be released with \c string_release using a matching \p allocator.
|
/// The returned buffer must be released with \c string_release using a matching \p allocator.
|
||||||
template<typename Allocator>
|
template<typename Allocator>
|
||||||
inline char* string_clone_range(const char* first, const char* last, Allocator& allocator)
|
inline char* string_clone_range(StringRange range, Allocator& allocator)
|
||||||
{
|
{
|
||||||
std::size_t length = last - first;
|
std::size_t length = range.last - range.first;
|
||||||
char* copied = strncpy(string_new(length, allocator), first, length);
|
char* copied = strncpy(string_new(length, allocator), range.first, length);
|
||||||
copied[length] = '\0';
|
copied[length] = '\0';
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
@ -224,10 +225,10 @@ inline char* string_clone(const char* other)
|
||||||
|
|
||||||
/// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
|
/// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
|
||||||
/// The returned buffer must be released with \c string_release.
|
/// The returned buffer must be released with \c string_release.
|
||||||
inline char* string_clone_range(const char* first, const char* last)
|
inline char* string_clone_range(StringRange range)
|
||||||
{
|
{
|
||||||
DefaultAllocator<char> allocator;
|
DefaultAllocator<char> allocator;
|
||||||
return string_clone_range(first, last, allocator);
|
return string_clone_range(range, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef char* char_pointer;
|
typedef char* char_pointer;
|
||||||
|
@ -343,8 +344,8 @@ public:
|
||||||
: Buffer(string)
|
: Buffer(string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
String(const char* first, const char* last)
|
String(StringRange range)
|
||||||
: Buffer(first, last)
|
: Buffer(range)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,6 +361,12 @@ public:
|
||||||
temp.swap(*this);
|
temp.swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
String& operator=(StringRange range)
|
||||||
|
{
|
||||||
|
String temp(range);
|
||||||
|
temp.swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void swap(String& other)
|
void swap(String& other)
|
||||||
{
|
{
|
||||||
|
@ -426,9 +433,9 @@ class CopiedBuffer : private Allocator
|
||||||
{
|
{
|
||||||
char* m_string;
|
char* m_string;
|
||||||
|
|
||||||
char* copy_range(const char* first, const char* last)
|
char* copy_range(StringRange range)
|
||||||
{
|
{
|
||||||
return string_clone_range(first, last, static_cast<Allocator&>(*this));
|
return string_clone_range(range, static_cast<Allocator&>(*this));
|
||||||
}
|
}
|
||||||
char* copy(const char* other)
|
char* copy(const char* other)
|
||||||
{
|
{
|
||||||
|
@ -461,8 +468,8 @@ public:
|
||||||
: Allocator(allocator), m_string(copy(string))
|
: Allocator(allocator), m_string(copy(string))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
CopiedBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
|
CopiedBuffer(StringRange range, const Allocator& allocator = Allocator())
|
||||||
: Allocator(allocator), m_string(copy_range(first, last))
|
: Allocator(allocator), m_string(copy_range(range))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
const char* c_str() const
|
const char* c_str() const
|
||||||
|
@ -485,11 +492,11 @@ class SmartBuffer : private Allocator
|
||||||
{
|
{
|
||||||
char* m_buffer;
|
char* m_buffer;
|
||||||
|
|
||||||
char* copy_range(const char* first, const char* last)
|
char* copy_range(StringRange range)
|
||||||
{
|
{
|
||||||
char* buffer = Allocator::allocate(sizeof(std::size_t) + (last - first) + 1);
|
char* buffer = Allocator::allocate(sizeof(std::size_t) + (range.last - range.first) + 1);
|
||||||
strncpy(buffer + sizeof(std::size_t), first, last - first);
|
strncpy(buffer + sizeof(std::size_t), range.first, range.last - range.first);
|
||||||
buffer[sizeof(std::size_t) + (last - first)] = '\0';
|
buffer[sizeof(std::size_t) + (range.last - range.first)] = '\0';
|
||||||
*reinterpret_cast<std::size_t*>(buffer) = 0;
|
*reinterpret_cast<std::size_t*>(buffer) = 0;
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -541,8 +548,8 @@ public:
|
||||||
{
|
{
|
||||||
incref(m_buffer);
|
incref(m_buffer);
|
||||||
}
|
}
|
||||||
SmartBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
|
SmartBuffer(StringRange range, const Allocator& allocator = Allocator())
|
||||||
: Allocator(allocator), m_buffer(copy_range(first, last))
|
: Allocator(allocator), m_buffer(copy_range(range))
|
||||||
{
|
{
|
||||||
incref(m_buffer);
|
incref(m_buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ inline name_t name_read(const char* name)
|
||||||
end = p;
|
end = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name_t(CopiedString(name, end), Postfix(end));
|
return name_t(CopiedString(StringRange(name, end)), Postfix(end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,11 @@ public:
|
||||||
{
|
{
|
||||||
return g_showAngles;
|
return g_showAngles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printStatistics() const
|
||||||
|
{
|
||||||
|
StringPool_analyse(EntityKeyValues::getPool());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Quake3EntityCreator g_Quake3EntityCreator;
|
Quake3EntityCreator g_Quake3EntityCreator;
|
||||||
|
|
|
@ -34,7 +34,7 @@ inline void parseTextureName(CopiedString& name, const char* token)
|
||||||
{
|
{
|
||||||
StringOutputStream cleaned(256);
|
StringOutputStream cleaned(256);
|
||||||
cleaned << PathCleaned(token);
|
cleaned << PathCleaned(token);
|
||||||
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModelSkinKey : public ModuleObserver
|
class ModelSkinKey : public ModuleObserver
|
||||||
|
|
|
@ -500,11 +500,11 @@ public:
|
||||||
typedef Value* const_iterator;
|
typedef Value* const_iterator;
|
||||||
const_iterator begin() const
|
const_iterator begin() const
|
||||||
{
|
{
|
||||||
return m_children.begin;
|
return m_children.first;
|
||||||
}
|
}
|
||||||
const_iterator end() const
|
const_iterator end() const
|
||||||
{
|
{
|
||||||
return m_children.end;
|
return m_children.last;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ inline void parseTextureName(CopiedString& name, const char* token)
|
||||||
{
|
{
|
||||||
StringOutputStream cleaned(256);
|
StringOutputStream cleaned(256);
|
||||||
cleaned << PathCleaned(token);
|
cleaned << PathCleaned(token);
|
||||||
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic renderable triangle surface
|
// generic renderable triangle surface
|
||||||
|
|
|
@ -51,7 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <glib/gslist.h>
|
#include <glib/gslist.h>
|
||||||
|
|
||||||
#include "debugging/debugging.h"
|
#include "debugging/debugging.h"
|
||||||
#include "string/string.h"
|
#include "string/pooledstring.h"
|
||||||
#include "math/vector.h"
|
#include "math/vector.h"
|
||||||
#include "generic/callback.h"
|
#include "generic/callback.h"
|
||||||
#include "generic/referencecounted.h"
|
#include "generic/referencecounted.h"
|
||||||
|
@ -225,21 +225,29 @@ Image* loadSpecial(void* environment, const char* name)
|
||||||
return GlobalTexturesCache().loadImage(name);
|
return GlobalTexturesCache().loadImage(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShaderPoolContext
|
||||||
|
{
|
||||||
|
};
|
||||||
|
typedef Static<StringPool, ShaderPoolContext> ShaderPool;
|
||||||
|
typedef PooledString<ShaderPool> ShaderString;
|
||||||
|
typedef ShaderString ShaderVariable;
|
||||||
|
typedef ShaderString ShaderValue;
|
||||||
|
typedef CopiedString TextureExpression;
|
||||||
|
|
||||||
// clean a texture name to the qtexture_t name format we use internally
|
// clean a texture name to the qtexture_t name format we use internally
|
||||||
// NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case
|
// NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case
|
||||||
// information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name,
|
// information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name,
|
||||||
// we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive.
|
// we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive.
|
||||||
//++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present
|
//++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present
|
||||||
void parseTextureName(CopiedString& name, const char* token)
|
template<typename StringType>
|
||||||
|
void parseTextureName(StringType& name, const char* token)
|
||||||
{
|
{
|
||||||
StringOutputStream cleaned(256);
|
StringOutputStream cleaned(256);
|
||||||
cleaned << PathCleaned(token);
|
cleaned << PathCleaned(token);
|
||||||
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
name = CopiedString(StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str()))).c_str(); // remove extension
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
|
bool Tokeniser_parseTextureName(Tokeniser& tokeniser, TextureExpression& name)
|
||||||
{
|
{
|
||||||
const char* token = tokeniser.getToken();
|
const char* token = tokeniser.getToken();
|
||||||
if(token == 0)
|
if(token == 0)
|
||||||
|
@ -251,13 +259,6 @@ bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseShaderName(CopiedString& name, const char* token)
|
|
||||||
{
|
|
||||||
StringOutputStream cleaned(256);
|
|
||||||
cleaned << PathCleaned(token);
|
|
||||||
name = cleaned.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
|
bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
|
||||||
{
|
{
|
||||||
const char* token = tokeniser.getToken();
|
const char* token = tokeniser.getToken();
|
||||||
|
@ -266,11 +267,11 @@ bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
|
||||||
Tokeniser_unexpectedError(tokeniser, token, "#shader-name");
|
Tokeniser_unexpectedError(tokeniser, token, "#shader-name");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
parseShaderName(name, token);
|
parseTextureName(name, token);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
|
bool Tokeniser_parseString(Tokeniser& tokeniser, ShaderString& string)
|
||||||
{
|
{
|
||||||
const char* token = tokeniser.getToken();
|
const char* token = tokeniser.getToken();
|
||||||
if(token == 0)
|
if(token == 0)
|
||||||
|
@ -284,12 +285,10 @@ bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::list<CopiedString> ShaderParameters;
|
typedef std::list<ShaderVariable> ShaderParameters;
|
||||||
typedef std::list<CopiedString> ShaderArguments;
|
typedef std::list<ShaderVariable> ShaderArguments;
|
||||||
|
|
||||||
typedef CopiedString TextureExpression;
|
typedef std::pair<ShaderVariable, ShaderVariable> BlendFuncExpression;
|
||||||
typedef CopiedString ShaderValue;
|
|
||||||
typedef std::pair<CopiedString, CopiedString> BlendFuncExpression;
|
|
||||||
|
|
||||||
class ShaderTemplate
|
class ShaderTemplate
|
||||||
{
|
{
|
||||||
|
@ -406,7 +405,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
|
bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
|
||||||
{
|
{
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
|
||||||
|
@ -416,20 +415,20 @@ bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, Copied
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, CopiedString& bump)
|
bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, TextureExpression& bump)
|
||||||
{
|
{
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "heightmap"));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "heightmap"));
|
||||||
CopiedString heightmapName;
|
TextureExpression heightmapName;
|
||||||
CopiedString heightmapScale;
|
ShaderValue heightmapScale;
|
||||||
RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, heightmapName, heightmapScale));
|
RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, heightmapName, heightmapScale));
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
|
bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
|
||||||
{
|
{
|
||||||
const char* token = tokeniser.getToken();
|
const char* token = tokeniser.getToken();
|
||||||
if(token == 0)
|
if(token == 0)
|
||||||
|
@ -465,7 +464,7 @@ class LayerTemplate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LayerTypeId m_type;
|
LayerTypeId m_type;
|
||||||
CopiedString m_texture;
|
TextureExpression m_texture;
|
||||||
BlendFuncExpression m_blendFunc;
|
BlendFuncExpression m_blendFunc;
|
||||||
bool m_clampToBorder;
|
bool m_clampToBorder;
|
||||||
ShaderValue m_alphaTest;
|
ShaderValue m_alphaTest;
|
||||||
|
@ -741,9 +740,9 @@ bool ShaderTemplate::parseDoom3(Tokeniser& tokeniser)
|
||||||
if(string_equal_nocase(lightFalloffImage, "makeintensity"))
|
if(string_equal_nocase(lightFalloffImage, "makeintensity"))
|
||||||
{
|
{
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
|
||||||
CopiedString name;
|
TextureExpression name;
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
|
||||||
m_lightFalloffImage = name.c_str();
|
m_lightFalloffImage = name;
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -797,7 +796,7 @@ ShaderDefinitionMap g_shaderDefinitions;
|
||||||
bool parseTemplateInstance(Tokeniser& tokeniser, const char* filename)
|
bool parseTemplateInstance(Tokeniser& tokeniser, const char* filename)
|
||||||
{
|
{
|
||||||
CopiedString name;
|
CopiedString name;
|
||||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
|
RETURN_FALSE_IF_FAIL(Tokeniser_parseShaderName(tokeniser, name));
|
||||||
const char* templateName = tokeniser.getToken();
|
const char* templateName = tokeniser.getToken();
|
||||||
ShaderTemplate* shaderTemplate = findTemplate(templateName);
|
ShaderTemplate* shaderTemplate = findTemplate(templateName);
|
||||||
if(shaderTemplate == 0)
|
if(shaderTemplate == 0)
|
||||||
|
@ -1312,7 +1311,7 @@ void FreeShaders()
|
||||||
bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
|
bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
|
||||||
{
|
{
|
||||||
// name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
|
// name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
|
||||||
m_textureName = m_Name;
|
m_textureName = m_Name.c_str();
|
||||||
|
|
||||||
tokeniser.nextLine();
|
tokeniser.nextLine();
|
||||||
|
|
||||||
|
@ -1486,7 +1485,7 @@ class Layer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LayerTypeId m_type;
|
LayerTypeId m_type;
|
||||||
CopiedString m_texture;
|
TextureExpression m_texture;
|
||||||
BlendFunc m_blendFunc;
|
BlendFunc m_blendFunc;
|
||||||
bool m_clampToBorder;
|
bool m_clampToBorder;
|
||||||
float m_alphaTest;
|
float m_alphaTest;
|
||||||
|
@ -1924,6 +1923,8 @@ void Shaders_Load()
|
||||||
lst = lst->next;
|
lst = lst->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//StringPool_analyse(ShaderPool::instance());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shaders_Free()
|
void Shaders_Free()
|
||||||
|
|
|
@ -486,7 +486,7 @@ public:
|
||||||
}
|
}
|
||||||
else // special key
|
else // special key
|
||||||
{
|
{
|
||||||
CopiedString keyName(value, keyEnd);
|
CopiedString keyName(StringRange(value, keyEnd));
|
||||||
accelerator.key = global_keys_find(keyName.c_str());
|
accelerator.key = global_keys_find(keyName.c_str());
|
||||||
if(accelerator.key != 0)
|
if(accelerator.key != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -558,7 +558,7 @@ void Dialog::addCombo(GtkWidget* vbox, const char* name, StringArrayRange values
|
||||||
{
|
{
|
||||||
GtkWidget* combo = gtk_combo_box_new_text();
|
GtkWidget* combo = gtk_combo_box_new_text();
|
||||||
|
|
||||||
for(StringArrayRange::Iterator i = values.begin; i != values.end; ++i)
|
for(StringArrayRange::Iterator i = values.first; i != values.last; ++i)
|
||||||
{
|
{
|
||||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), *i);
|
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), *i);
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ void Dialog::addRadio(GtkWidget* vbox, const char* name, int& data, StringArrayR
|
||||||
|
|
||||||
void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange icons, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
|
void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange icons, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
|
||||||
{
|
{
|
||||||
GtkWidget* table = gtk_table_new (2, static_cast<guint>(icons.end - icons.begin), FALSE);
|
GtkWidget* table = gtk_table_new (2, static_cast<guint>(icons.last - icons.first), FALSE);
|
||||||
gtk_widget_show (table);
|
gtk_widget_show (table);
|
||||||
|
|
||||||
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
|
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
|
||||||
|
@ -648,9 +648,9 @@ void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange i
|
||||||
|
|
||||||
GSList* group = 0;
|
GSList* group = 0;
|
||||||
GtkWidget* radio = 0;
|
GtkWidget* radio = 0;
|
||||||
for(StringArrayRange::Iterator icon = icons.begin; icon != icons.end; ++icon)
|
for(StringArrayRange::Iterator icon = icons.first; icon != icons.last; ++icon)
|
||||||
{
|
{
|
||||||
guint pos = static_cast<guint>(icon - icons.begin);
|
guint pos = static_cast<guint>(icon - icons.first);
|
||||||
GtkImage* image = new_local_image(*icon);
|
GtkImage* image = new_local_image(*icon);
|
||||||
gtk_widget_show(GTK_WIDGET(image));
|
gtk_widget_show(GTK_WIDGET(image));
|
||||||
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(image), pos, pos+1, 0, 1,
|
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(image), pos, pos+1, 0, 1,
|
||||||
|
|
|
@ -182,7 +182,7 @@ void setSpecialLoad(EntityClass *e, const char* pWhat, CopiedString& p)
|
||||||
where = strchr(pText,'\"');
|
where = strchr(pText,'\"');
|
||||||
if (where)
|
if (where)
|
||||||
{
|
{
|
||||||
p = CopiedString(pText, where);
|
p = StringRange(pText, where);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -313,7 +313,7 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
||||||
const char* key = tokeniser.getToken();
|
const char* key = tokeniser.getToken();
|
||||||
|
|
||||||
const char* last = string_findFirstSpaceOrTab(key);
|
const char* last = string_findFirstSpaceOrTab(key);
|
||||||
CopiedString first(key, last);
|
CopiedString first(StringRange(key, last));
|
||||||
|
|
||||||
if(!string_empty(last))
|
if(!string_empty(last))
|
||||||
{
|
{
|
||||||
|
|
|
@ -619,3 +619,4 @@ int main (int argc, char* argv[])
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1046,6 +1046,8 @@ void Map_LoadFile (const char *filename)
|
||||||
|
|
||||||
globalOutputStream() << makeLeftJustified(Unsigned(g_brushCount.get()), 5) << " primitive\n";
|
globalOutputStream() << makeLeftJustified(Unsigned(g_brushCount.get()), 5) << " primitive\n";
|
||||||
globalOutputStream() << makeLeftJustified(Unsigned(g_entityCount.get()), 5) << " entities\n";
|
globalOutputStream() << makeLeftJustified(Unsigned(g_entityCount.get()), 5) << " entities\n";
|
||||||
|
|
||||||
|
//GlobalEntityCreator().printStatistics();
|
||||||
|
|
||||||
//
|
//
|
||||||
// move the view to a start position
|
// move the view to a start position
|
||||||
|
|
|
@ -159,9 +159,9 @@ void texturegroup_activated(GtkWidget* widget, gpointer data)
|
||||||
reinterpret_cast<TextureGroupLoader*>(data)->loadGroup();
|
reinterpret_cast<TextureGroupLoader*>(data)->loadGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_equal_start(const char* string, const char* start)
|
bool string_equal_start(const char* string, StringRange start)
|
||||||
{
|
{
|
||||||
return string_equal_n(string, start, string_length(start));
|
return string_equal_n(string, start.first, start.last - start.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkMenuItem* MenuItem_create(const char* name)
|
GtkMenuItem* MenuItem_create(const char* name)
|
||||||
|
@ -210,7 +210,7 @@ void TextureGroupsMenu_Construct(GtkMenu* menu, const TextureGroups& groups)
|
||||||
{
|
{
|
||||||
const char* dirName = (*i).c_str();
|
const char* dirName = (*i).c_str();
|
||||||
const char* firstUnderscore = strchr(dirName, '_');
|
const char* firstUnderscore = strchr(dirName, '_');
|
||||||
CopiedString dirRoot(dirName, (firstUnderscore == 0) ? dirName : firstUnderscore + 1);
|
StringRange dirRoot(dirName, (firstUnderscore == 0) ? dirName : firstUnderscore + 1);
|
||||||
|
|
||||||
// do we shrink the menus?
|
// do we shrink the menus?
|
||||||
// we shrink only if we have at least two things to shrink :-)
|
// we shrink only if we have at least two things to shrink :-)
|
||||||
|
@ -218,16 +218,15 @@ void TextureGroupsMenu_Construct(GtkMenu* menu, const TextureGroups& groups)
|
||||||
++next;
|
++next;
|
||||||
if(firstUnderscore != 0
|
if(firstUnderscore != 0
|
||||||
&& next != groups.end()
|
&& next != groups.end()
|
||||||
&& string_equal_start((*next).c_str(), dirRoot.c_str()))
|
&& string_equal_start((*next).c_str(), dirRoot))
|
||||||
{
|
{
|
||||||
CopiedString itemName(dirName, firstUnderscore);
|
GtkMenuItem* item = Menu_addItem(menu, CopiedString(StringRange(dirName, firstUnderscore)).c_str());
|
||||||
GtkMenuItem* item = Menu_addItem(menu, itemName.c_str());
|
|
||||||
|
|
||||||
GtkMenu *pSubMenu = GTK_MENU(gtk_menu_new());
|
GtkMenu *pSubMenu = GTK_MENU(gtk_menu_new());
|
||||||
gtk_menu_item_set_submenu(item, GTK_WIDGET(pSubMenu));
|
gtk_menu_item_set_submenu(item, GTK_WIDGET(pSubMenu));
|
||||||
|
|
||||||
// keep going...
|
// keep going...
|
||||||
while(i != groups.end() && string_equal_start((*i).c_str(), dirRoot.c_str()))
|
while(i != groups.end() && string_equal_start((*i).c_str(), dirRoot))
|
||||||
{
|
{
|
||||||
TextureGroupsMenu_addItem(pSubMenu, (*i).c_str());
|
TextureGroupsMenu_addItem(pSubMenu, (*i).c_str());
|
||||||
|
|
||||||
|
@ -266,7 +265,7 @@ void TextureGroups_addShader(TextureGroups& groups, const char* shaderName)
|
||||||
const char* last = path_remove_directory(texture);
|
const char* last = path_remove_directory(texture);
|
||||||
if(!string_empty(last))
|
if(!string_empty(last))
|
||||||
{
|
{
|
||||||
groups.insert(CopiedString(texture, --last));
|
groups.insert(CopiedString(StringRange(texture, --last)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -811,8 +810,7 @@ class LoadShaderVisitor : public Archive::Visitor
|
||||||
public:
|
public:
|
||||||
void visit(const char* name)
|
void visit(const char* name)
|
||||||
{
|
{
|
||||||
CopiedString shaderName(name, path_get_filename_base_end(name));
|
IShader* shader = QERApp_Shader_ForName(CopiedString(StringRange(name, path_get_filename_base_end(name))).c_str());
|
||||||
IShader* shader = QERApp_Shader_ForName(shaderName.c_str());
|
|
||||||
shader->DecRef();
|
shader->DecRef();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1152,7 +1152,7 @@ public:
|
||||||
{
|
{
|
||||||
popMenu();
|
popMenu();
|
||||||
}
|
}
|
||||||
pushMenu(CopiedString(name, underscore));
|
pushMenu(CopiedString(StringRange(name, underscore)));
|
||||||
}
|
}
|
||||||
else if(m_stack.size() == 2)
|
else if(m_stack.size() == 2)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue