3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #ifndef UTILITY_HEADER
21 #define UTILITY_HEADER
29 #include <jmutexautolock.h>
31 #include "common_irrlicht.h"
34 #include "exceptions.h"
37 extern const v3s16 g_26dirs[26];
39 inline void writeU32(u8 *data, u32 i)
41 data[0] = ((i>>24)&0xff);
42 data[1] = ((i>>16)&0xff);
43 data[2] = ((i>> 8)&0xff);
44 data[3] = ((i>> 0)&0xff);
47 inline void writeU16(u8 *data, u16 i)
49 data[0] = ((i>> 8)&0xff);
50 data[1] = ((i>> 0)&0xff);
53 inline void writeU8(u8 *data, u8 i)
55 data[0] = ((i>> 0)&0xff);
58 inline u32 readU32(u8 *data)
60 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
63 inline u16 readU16(u8 *data)
65 return (data[0]<<8) | (data[1]<<0);
68 inline u8 readU8(u8 *data)
73 // Signed variants of the above
75 inline void writeS32(u8 *data, s32 i){
76 writeU32(data, (u32)i);
78 inline s32 readS32(u8 *data){
79 return (s32)readU32(data);
82 inline void writeS16(u8 *data, s16 i){
83 writeU16(data, (u16)i);
85 inline s16 readS16(u8 *data){
86 return (s16)readU16(data);
89 inline void writeV3S32(u8 *data, v3s32 p)
91 writeS32(&data[0], p.X);
92 writeS32(&data[4], p.Y);
93 writeS32(&data[8], p.Z);
96 inline v3s32 readV3S32(u8 *data)
99 p.X = readS32(&data[0]);
100 p.Y = readS32(&data[4]);
101 p.Z = readS32(&data[8]);
105 inline void writeV2S16(u8 *data, v2s16 p)
107 writeS16(&data[0], p.X);
108 writeS16(&data[2], p.Y);
111 inline v2s16 readV2S16(u8 *data)
114 p.X = readS16(&data[0]);
115 p.Y = readS16(&data[2]);
119 inline void writeV2S32(u8 *data, v2s32 p)
121 writeS32(&data[0], p.X);
122 writeS32(&data[2], p.Y);
125 inline v2s32 readV2S32(u8 *data)
128 p.X = readS32(&data[0]);
129 p.Y = readS32(&data[2]);
133 inline void writeV3S16(u8 *data, v3s16 p)
135 writeS16(&data[0], p.X);
136 writeS16(&data[2], p.Y);
137 writeS16(&data[4], p.Z);
140 inline v3s16 readV3S16(u8 *data)
143 p.X = readS16(&data[0]);
144 p.Y = readS16(&data[2]);
145 p.Z = readS16(&data[4]);
150 None of these are used at the moment
153 template <typename T>
163 SharedPtr(SharedPtr<T> &t)
167 refcount = t.refcount;
175 SharedPtr<T> & operator=(T *t)
183 SharedPtr<T> & operator=(SharedPtr<T> &t)
186 refcount = t.refcount;
199 bool operator!=(T *t)
203 bool operator==(T *t)
210 assert((*refcount) > 0);
223 template <typename T>
227 Buffer(unsigned int size)
232 Buffer(const Buffer &buffer)
234 m_size = buffer.m_size;
235 data = new T[buffer.m_size];
236 memcpy(data, buffer.data, buffer.m_size);
238 Buffer(T *t, unsigned int size)
242 memcpy(data, t, size);
248 T & operator[](unsigned int i) const
252 T * operator*() const
256 unsigned int getSize() const
265 template <typename T>
269 SharedBuffer(unsigned int size)
273 refcount = new unsigned int;
276 SharedBuffer(const SharedBuffer &buffer)
278 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
279 m_size = buffer.m_size;
281 refcount = buffer.refcount;
284 SharedBuffer & operator=(const SharedBuffer & buffer)
286 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
290 m_size = buffer.m_size;
292 refcount = buffer.refcount;
299 SharedBuffer(T *t, unsigned int size)
303 memcpy(data, t, size);
304 refcount = new unsigned int;
310 SharedBuffer(const Buffer<T> &buffer)
312 m_size = buffer.m_size;
313 data = new T[buffer.getSize()];
314 memcpy(data, *buffer, buffer.getSize());
315 refcount = new unsigned int;
322 T & operator[](unsigned int i) const
326 T * operator*() const
330 unsigned int getSize() const
337 assert((*refcount) > 0);
347 unsigned int *refcount;
350 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
352 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
357 class MutexedVariable
360 MutexedVariable(T value):
368 JMutexAutoLock lock(m_mutex);
374 JMutexAutoLock lock(m_mutex);
378 // You'll want to grab this in a SharedPtr
379 JMutexAutoLock * getLock()
381 return new JMutexAutoLock(m_mutex);
384 // You pretty surely want to grab the lock when accessing this
395 class IrrlichtWrapper;
400 TimeTaker(const char *name, u32 *result=NULL);
407 u32 stop(bool quiet=false);
416 // Calculates the borders of a "d-radius" cube
417 inline void getFacePositions(core::list<v3s16> &list, u16 d)
421 list.push_back(v3s16(0,0,0));
427 This is an optimized sequence of coordinates.
429 list.push_back(v3s16( 0, 1, 0)); // top
430 list.push_back(v3s16( 0, 0, 1)); // back
431 list.push_back(v3s16(-1, 0, 0)); // left
432 list.push_back(v3s16( 1, 0, 0)); // right
433 list.push_back(v3s16( 0, 0,-1)); // front
434 list.push_back(v3s16( 0,-1, 0)); // bottom
436 list.push_back(v3s16(-1, 0, 1)); // back left
437 list.push_back(v3s16( 1, 0, 1)); // back right
438 list.push_back(v3s16(-1, 0,-1)); // front left
439 list.push_back(v3s16( 1, 0,-1)); // front right
440 list.push_back(v3s16(-1,-1, 0)); // bottom left
441 list.push_back(v3s16( 1,-1, 0)); // bottom right
442 list.push_back(v3s16( 0,-1, 1)); // bottom back
443 list.push_back(v3s16( 0,-1,-1)); // bottom front
444 list.push_back(v3s16(-1, 1, 0)); // top left
445 list.push_back(v3s16( 1, 1, 0)); // top right
446 list.push_back(v3s16( 0, 1, 1)); // top back
447 list.push_back(v3s16( 0, 1,-1)); // top front
449 list.push_back(v3s16(-1, 1, 1)); // top back-left
450 list.push_back(v3s16( 1, 1, 1)); // top back-right
451 list.push_back(v3s16(-1, 1,-1)); // top front-left
452 list.push_back(v3s16( 1, 1,-1)); // top front-right
453 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
454 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
455 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
456 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
461 // Take blocks in all sides, starting from y=0 and going +-y
462 for(s16 y=0; y<=d-1; y++)
464 // Left and right side, including borders
465 for(s16 z=-d; z<=d; z++)
467 list.push_back(v3s16(d,y,z));
468 list.push_back(v3s16(-d,y,z));
471 list.push_back(v3s16(d,-y,z));
472 list.push_back(v3s16(-d,-y,z));
475 // Back and front side, excluding borders
476 for(s16 x=-d+1; x<=d-1; x++)
478 list.push_back(v3s16(x,y,d));
479 list.push_back(v3s16(x,y,-d));
482 list.push_back(v3s16(x,-y,d));
483 list.push_back(v3s16(x,-y,-d));
488 // Take the bottom and top face with borders
489 // -d<x<d, y=+-d, -d<z<d
490 for(s16 x=-d; x<=d; x++)
491 for(s16 z=-d; z<=d; z++)
493 list.push_back(v3s16(x,-d,z));
494 list.push_back(v3s16(x,d,z));
498 class IndentationRaiser
501 IndentationRaiser(u16 *indentation)
503 m_indentation = indentation;
514 inline s16 getContainerPos(s16 p, s16 d)
516 return (p>=0 ? p : p-d+1) / d;
519 inline v2s16 getContainerPos(v2s16 p, s16 d)
522 getContainerPos(p.X, d),
523 getContainerPos(p.Y, d)
527 inline v3s16 getContainerPos(v3s16 p, s16 d)
530 getContainerPos(p.X, d),
531 getContainerPos(p.Y, d),
532 getContainerPos(p.Z, d)
536 inline bool isInArea(v3s16 p, s16 d)
539 p.X >= 0 && p.X < d &&
540 p.Y >= 0 && p.Y < d &&
545 inline bool isInArea(v2s16 p, s16 d)
548 p.X >= 0 && p.X < d &&
553 inline std::wstring narrow_to_wide(const std::string& mbs)
555 size_t wcl = mbs.size();
556 SharedBuffer<wchar_t> wcs(wcl+1);
557 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
562 inline std::string wide_to_narrow(const std::wstring& wcs)
564 size_t mbl = wcs.size()*4;
565 SharedBuffer<char> mbs(mbl+1);
566 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
575 See test.cpp for example cases.
576 wraps degrees to the range of -360...360
577 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
579 inline float wrapDegrees(float f)
581 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
587 // NOTE: This would be used for wrapping to 0...360
593 // 10, 0.5, -0.5, -0.5
598 inline std::string lowercase(std::string s)
600 for(size_t i=0; i<s.size(); i++)
602 if(s[i] >= 'A' && s[i] <= 'Z')
608 inline bool is_yes(std::string s)
610 s = lowercase(trim(s));
611 if(s == "y" || s == "yes" || s == "true")
616 inline s32 stoi(std::string s, s32 min, s32 max)
618 s32 i = atoi(s.c_str());
626 inline s32 stoi(std::string s)
628 return atoi(s.c_str());
632 A base class for simple background thread implementation
635 class SimpleThread : public JThread
649 virtual ~SimpleThread()
652 virtual void * Thread() = 0;
656 JMutexAutoLock lock(run_mutex);
659 void setRun(bool a_run)
661 JMutexAutoLock lock(run_mutex);
680 VALUETYPE_FLAG // Doesn't take any arguments
685 ValueSpec(ValueType a_type, const char *a_help=NULL)
698 // Returns false on EOF
699 bool parseConfigObject(std::istream &is)
704 // NOTE: This function will be expanded to allow multi-line settings
706 std::getline(is, line);
707 //dstream<<"got line: \""<<line<<"\""<<std::endl;
709 std::string trimmedline = trim(line);
712 if(trimmedline[0] == '#')
715 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
717 Strfnd sf(trim(line));
719 std::string name = sf.next("=");
725 std::string value = sf.next("\n");
728 dstream<<"Config name=\""<<name<<"\" value=\""
729 <<value<<"\""<<std::endl;
731 m_settings[name] = value;
737 Read configuration file
739 Returns true on success
741 bool readConfigFile(const char *filename)
743 std::ifstream is(filename);
744 if(is.good() == false)
746 dstream<<"Error opening configuration file \""
747 <<filename<<"\""<<std::endl;
751 dstream<<"Parsing configuration file: \""
752 <<filename<<"\""<<std::endl;
754 while(parseConfigObject(is));
760 Reads a configuration object from stream (usually a single line)
763 Preserves comments and empty lines.
765 Settings that were added to dst are also added to updated.
766 key of updated is setting name, value of updated is dummy.
770 bool getUpdatedConfigObject(std::istream &is,
771 core::list<std::string> &dst,
772 core::map<std::string, bool> &updated)
777 // NOTE: This function will be expanded to allow multi-line settings
779 std::getline(is, line);
781 std::string trimmedline = trim(line);
783 std::string line_end = "";
784 if(is.eof() == false)
788 if(trimmedline[0] == '#')
790 dst.push_back(line+line_end);
794 Strfnd sf(trim(line));
796 std::string name = sf.next("=");
801 dst.push_back(line+line_end);
805 std::string value = sf.next("\n");
808 if(m_settings.find(name))
810 std::string newvalue = m_settings[name];
812 if(newvalue != value)
814 dstream<<"Changing value of \""<<name<<"\" = \""
815 <<value<<"\" -> \""<<newvalue<<"\""
819 dst.push_back(name + " = " + newvalue + line_end);
821 updated[name] = true;
828 Updates configuration file
830 Returns true on success
832 bool updateConfigFile(const char *filename)
834 dstream<<"Updating configuration file: \""
835 <<filename<<"\""<<std::endl;
837 core::list<std::string> objects;
838 core::map<std::string, bool> updated;
840 // Read and modify stuff
842 std::ifstream is(filename);
843 if(is.good() == false)
845 dstream<<"Error opening configuration file"
847 <<filename<<"\""<<std::endl;
851 while(getUpdatedConfigObject(is, objects, updated));
856 std::ofstream os(filename);
857 if(os.good() == false)
859 dstream<<"Error opening configuration file"
861 <<filename<<"\""<<std::endl;
868 for(core::list<std::string>::Iterator
870 i != objects.end(); i++)
876 Write stuff that was not already in the file
878 for(core::map<std::string, std::string>::Iterator
879 i = m_settings.getIterator();
880 i.atEnd() == false; i++)
882 if(updated.find(i.getNode()->getKey()))
884 std::string name = i.getNode()->getKey();
885 std::string value = i.getNode()->getValue();
886 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
888 os<<name<<" = "<<value<<"\n";
896 NOTE: Types of allowed_options are ignored
898 returns true on success
900 bool parseCommandLine(int argc, char *argv[],
901 core::map<std::string, ValueSpec> &allowed_options)
908 std::string argname = argv[i];
909 if(argname.substr(0, 2) != "--")
911 dstream<<"Invalid command-line parameter \""
912 <<argname<<"\": --<option> expected."<<std::endl;
917 std::string name = argname.substr(2);
919 core::map<std::string, ValueSpec>::Node *n;
920 n = allowed_options.find(name);
923 dstream<<"Unknown command-line parameter \""
924 <<argname<<"\""<<std::endl;
928 ValueType type = n->getValue().type;
930 std::string value = "";
932 if(type == VALUETYPE_FLAG)
940 dstream<<"Invalid command-line parameter \""
941 <<name<<"\": missing value"<<std::endl;
949 dstream<<"Valid command-line parameter: \""
950 <<name<<"\" = \""<<value<<"\""
958 void set(std::string name, std::string value)
960 m_settings[name] = value;
963 void setDefault(std::string name, std::string value)
965 m_defaults[name] = value;
968 bool exists(std::string name)
970 return (m_settings.find(name) || m_defaults.find(name));
973 std::string get(std::string name)
975 core::map<std::string, std::string>::Node *n;
976 n = m_settings.find(name);
979 n = m_defaults.find(name);
982 throw SettingNotFoundException("Setting not found");
986 return n->getValue();
989 bool getBool(std::string name)
991 return is_yes(get(name));
994 bool getFlag(std::string name)
998 return getBool(name);
1000 catch(SettingNotFoundException &e)
1007 bool getBoolAsk(std::string name, std::string question, bool def)
1009 std::string s = get(name);
1014 std::cout<<question<<" [y/N]: ";
1015 std::cin.getline(templine, 10);
1024 float getFloat(std::string name)
1027 std::istringstream vis(get(name));
1032 u16 getU16(std::string name)
1034 return stoi(get(name), 0, 65535);
1037 u16 getU16Ask(std::string name, std::string question, u16 def)
1039 std::string s = get(name);
1041 return stoi(s, 0, 65535);
1044 std::cout<<question<<" ["<<def<<"]: ";
1045 std::cin.getline(templine, 10);
1051 return stoi(s, 0, 65535);
1054 s16 getS16(std::string name)
1056 return stoi(get(name), -32768, 32767);
1059 s32 getS32(std::string name)
1061 return stoi(get(name));
1065 core::map<std::string, std::string> m_settings;
1066 core::map<std::string, std::string> m_defaults;
1073 template<typename T>
1083 return m_list.size();
1087 JMutexAutoLock lock(m_mutex);
1088 m_list.push_back(t);
1090 T pop_front(u32 wait_time_max_ms=0)
1092 u32 wait_time_ms = 0;
1097 JMutexAutoLock lock(m_mutex);
1099 if(m_list.size() > 0)
1101 typename core::list<T>::Iterator begin = m_list.begin();
1103 m_list.erase(begin);
1107 if(wait_time_ms >= wait_time_max_ms)
1108 throw ItemNotFoundException("MutexedQueue: queue is empty");
1111 // Wait a while before trying again
1122 core::list<T> & getList()
1129 core::list<T> m_list;
1132 template<typename Caller, typename Data>
1140 template<typename Key, typename T, typename Caller, typename CallerData>
1146 core::list<CallerInfo<Caller, CallerData> > callers;
1149 template<typename Key, typename T, typename Caller, typename CallerData>
1150 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1154 template<typename Key, typename T, typename Caller, typename CallerData>
1162 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1166 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1177 ResultQueue<Key, T, Caller, CallerData> *dest;
1178 core::list<CallerInfo<Caller, CallerData> > callers;
1182 Quickhands for typical request-result queues.
1183 Used for distributing work between threads.
1186 template<typename Key, typename T, typename Caller, typename CallerData>
1192 return m_queue.size();
1195 void add(Key key, Caller caller, CallerData callerdata,
1196 ResultQueue<Key, T, Caller, CallerData> *dest)
1198 JMutexAutoLock lock(m_queue.getMutex());
1201 If the caller is already on the list, only update CallerData
1203 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1204 i = m_queue.getList().begin();
1205 i != m_queue.getList().end(); i++)
1207 GetRequest<Key, T, Caller, CallerData> &request = *i;
1209 if(request.key == key)
1211 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1212 i = request.callers.begin();
1213 i != request.callers.end(); i++)
1215 CallerInfo<Caller, CallerData> &ca = *i;
1216 if(ca.caller == caller)
1218 ca.data = callerdata;
1222 CallerInfo<Caller, CallerData> ca;
1224 ca.data = callerdata;
1225 request.callers.push_back(ca);
1231 Else add a new request to the queue
1234 GetRequest<Key, T, Caller, CallerData> request;
1236 CallerInfo<Caller, CallerData> ca;
1238 ca.data = callerdata;
1239 request.callers.push_back(ca);
1240 request.dest = dest;
1242 m_queue.getList().push_back(request);
1245 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1247 return m_queue.pop_front(wait_if_empty);
1251 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;