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.
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
24 #ifndef UTILITY_HEADER
25 #define UTILITY_HEADER
32 #include <jmutexautolock.h>
34 #include "common_irrlicht.h"
37 #include "exceptions.h"
39 extern const v3s16 g_26dirs[26];
41 inline void writeU32(u8 *data, u32 i)
43 data[0] = ((i>>24)&0xff);
44 data[1] = ((i>>16)&0xff);
45 data[2] = ((i>> 8)&0xff);
46 data[3] = ((i>> 0)&0xff);
49 inline void writeU16(u8 *data, u16 i)
51 data[0] = ((i>> 8)&0xff);
52 data[1] = ((i>> 0)&0xff);
55 inline void writeU8(u8 *data, u8 i)
57 data[0] = ((i>> 0)&0xff);
60 inline u32 readU32(u8 *data)
62 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
65 inline u16 readU16(u8 *data)
67 return (data[0]<<8) | (data[1]<<0);
70 inline u8 readU8(u8 *data)
75 // Signed variants of the above
77 inline void writeS32(u8 *data, s32 i){
78 writeU32(data, (u32)i);
80 inline s32 readS32(u8 *data){
81 return (s32)readU32(data);
84 inline void writeS16(u8 *data, s16 i){
85 writeU16(data, (u16)i);
87 inline s16 readS16(u8 *data){
88 return (s16)readU16(data);
91 inline void writeV3S32(u8 *data, v3s32 p)
93 writeS32(&data[0], p.X);
94 writeS32(&data[4], p.Y);
95 writeS32(&data[8], p.Z);
98 inline v3s32 readV3S32(u8 *data)
101 p.X = readS32(&data[0]);
102 p.Y = readS32(&data[4]);
103 p.Z = readS32(&data[8]);
107 inline void writeV2S16(u8 *data, v2s16 p)
109 writeS16(&data[0], p.X);
110 writeS16(&data[2], p.Y);
113 inline v2s16 readV2S16(u8 *data)
116 p.X = readS16(&data[0]);
117 p.Y = readS16(&data[2]);
121 inline void writeV2S32(u8 *data, v2s32 p)
123 writeS32(&data[0], p.X);
124 writeS32(&data[2], p.Y);
127 inline v2s32 readV2S32(u8 *data)
130 p.X = readS32(&data[0]);
131 p.Y = readS32(&data[2]);
135 inline void writeV3S16(u8 *data, v3s16 p)
137 writeS16(&data[0], p.X);
138 writeS16(&data[2], p.Y);
139 writeS16(&data[4], p.Z);
142 inline v3s16 readV3S16(u8 *data)
145 p.X = readS16(&data[0]);
146 p.Y = readS16(&data[2]);
147 p.Z = readS16(&data[4]);
152 None of these are used at the moment
155 template <typename T>
165 SharedPtr(SharedPtr<T> &t)
169 refcount = t.refcount;
177 SharedPtr<T> & operator=(T *t)
185 SharedPtr<T> & operator=(SharedPtr<T> &t)
188 refcount = t.refcount;
201 bool operator!=(T *t)
205 bool operator==(T *t)
212 assert((*refcount) > 0);
225 template <typename T>
229 Buffer(unsigned int size)
234 Buffer(const Buffer &buffer)
236 m_size = buffer.m_size;
237 data = new T[buffer.m_size];
238 memcpy(data, buffer.data, buffer.m_size);
240 Buffer(T *t, unsigned int size)
244 memcpy(data, t, size);
250 T & operator[](unsigned int i) const
254 T * operator*() const
258 unsigned int getSize() const
267 template <typename T>
271 SharedBuffer(unsigned int size)
275 refcount = new unsigned int;
278 SharedBuffer(const SharedBuffer &buffer)
280 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
281 m_size = buffer.m_size;
283 refcount = buffer.refcount;
286 SharedBuffer & operator=(const SharedBuffer & buffer)
288 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
292 m_size = buffer.m_size;
294 refcount = buffer.refcount;
301 SharedBuffer(T *t, unsigned int size)
305 memcpy(data, t, size);
306 refcount = new unsigned int;
312 SharedBuffer(const Buffer<T> &buffer)
314 m_size = buffer.m_size;
315 data = new T[buffer.getSize()];
316 memcpy(data, *buffer, buffer.getSize());
317 refcount = new unsigned int;
324 T & operator[](unsigned int i) const
328 T * operator*() const
332 unsigned int getSize() const
339 assert((*refcount) > 0);
349 unsigned int *refcount;
352 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
354 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
359 class MutexedVariable
362 MutexedVariable(T value):
370 JMutexAutoLock lock(m_mutex);
376 JMutexAutoLock lock(m_mutex);
380 // You'll want to grab this in a SharedPtr
381 JMutexAutoLock * getLock()
383 return new JMutexAutoLock(m_mutex);
386 // You pretty surely want to grab the lock when accessing this
400 TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
411 m_time1 = m_dev->getTimer()->getRealTime();
417 u32 stop(bool quiet=false)
424 std::cout<<"Couldn't measure time for "<<m_name
425 <<": dev==NULL"<<std::endl;*/
428 u32 time2 = m_dev->getTimer()->getRealTime();
429 u32 dtime = time2 - m_time1;
432 (*m_result) += dtime;
437 std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
446 IrrlichtDevice *m_dev;
452 // Calculates the borders of a "d-radius" cube
453 inline void getFacePositions(core::list<v3s16> &list, u16 d)
457 list.push_back(v3s16(0,0,0));
463 This is an optimized sequence of coordinates.
465 list.push_back(v3s16( 0, 1, 0)); // top
466 list.push_back(v3s16( 0, 0, 1)); // back
467 list.push_back(v3s16(-1, 0, 0)); // left
468 list.push_back(v3s16( 1, 0, 0)); // right
469 list.push_back(v3s16( 0, 0,-1)); // front
470 list.push_back(v3s16( 0,-1, 0)); // bottom
472 list.push_back(v3s16(-1, 0, 1)); // back left
473 list.push_back(v3s16( 1, 0, 1)); // back right
474 list.push_back(v3s16(-1, 0,-1)); // front left
475 list.push_back(v3s16( 1, 0,-1)); // front right
476 list.push_back(v3s16(-1,-1, 0)); // bottom left
477 list.push_back(v3s16( 1,-1, 0)); // bottom right
478 list.push_back(v3s16( 0,-1, 1)); // bottom back
479 list.push_back(v3s16( 0,-1,-1)); // bottom front
480 list.push_back(v3s16(-1, 1, 0)); // top left
481 list.push_back(v3s16( 1, 1, 0)); // top right
482 list.push_back(v3s16( 0, 1, 1)); // top back
483 list.push_back(v3s16( 0, 1,-1)); // top front
485 list.push_back(v3s16(-1, 1, 1)); // top back-left
486 list.push_back(v3s16( 1, 1, 1)); // top back-right
487 list.push_back(v3s16(-1, 1,-1)); // top front-left
488 list.push_back(v3s16( 1, 1,-1)); // top front-right
489 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
490 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
491 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
492 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
497 // Take blocks in all sides, starting from y=0 and going +-y
498 for(s16 y=0; y<=d-1; y++)
500 // Left and right side, including borders
501 for(s16 z=-d; z<=d; z++)
503 list.push_back(v3s16(d,y,z));
504 list.push_back(v3s16(-d,y,z));
507 list.push_back(v3s16(d,-y,z));
508 list.push_back(v3s16(-d,-y,z));
511 // Back and front side, excluding borders
512 for(s16 x=-d+1; x<=d-1; x++)
514 list.push_back(v3s16(x,y,d));
515 list.push_back(v3s16(x,y,-d));
518 list.push_back(v3s16(x,-y,d));
519 list.push_back(v3s16(x,-y,-d));
524 // Take the bottom and top face with borders
525 // -d<x<d, y=+-d, -d<z<d
526 for(s16 x=-d; x<=d; x++)
527 for(s16 z=-d; z<=d; z++)
529 list.push_back(v3s16(x,-d,z));
530 list.push_back(v3s16(x,d,z));
534 class IndentationRaiser
537 IndentationRaiser(u16 *indentation)
539 m_indentation = indentation;
550 inline s16 getContainerPos(s16 p, s16 d)
552 return (p>=0 ? p : p-d+1) / d;
555 inline v2s16 getContainerPos(v2s16 p, s16 d)
558 getContainerPos(p.X, d),
559 getContainerPos(p.Y, d)
563 inline v3s16 getContainerPos(v3s16 p, s16 d)
566 getContainerPos(p.X, d),
567 getContainerPos(p.Y, d),
568 getContainerPos(p.Z, d)
572 inline bool isInArea(v3s16 p, s16 d)
575 p.X >= 0 && p.X < d &&
576 p.Y >= 0 && p.Y < d &&
581 inline bool isInArea(v2s16 p, s16 d)
584 p.X >= 0 && p.X < d &&
589 inline std::wstring narrow_to_wide(const std::string& mbs)
591 size_t wcl = mbs.size();
592 SharedBuffer<wchar_t> wcs(wcl+1);
593 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
598 inline std::string wide_to_narrow(const std::wstring& wcs)
600 size_t mbl = wcs.size()*4;
601 SharedBuffer<char> mbs(mbl+1);
602 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
611 See test.cpp for example cases.
612 wraps degrees to the range of -360...360
613 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
615 inline float wrapDegrees(float f)
617 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
623 // NOTE: This would be used for wrapping to 0...360
629 // 10, 0.5, -0.5, -0.5
634 inline std::string lowercase(std::string s)
636 for(size_t i=0; i<s.size(); i++)
638 if(s[i] >= 'A' && s[i] <= 'Z')
644 inline bool is_yes(std::string s)
646 s = lowercase(trim(s));
647 if(s == "y" || s == "yes" || s == "true")
652 inline s32 stoi(std::string s, s32 min, s32 max)
654 s32 i = atoi(s.c_str());
662 inline s32 stoi(std::string s)
664 return atoi(s.c_str());
674 VALUETYPE_FLAG // Doesn't take any arguments
679 ValueSpec(ValueType a_type, const char *a_help=NULL)
692 // Returns false on EOF
693 bool parseConfigObject(std::istream &is)
698 // NOTE: This function will be expanded to allow multi-line settings
700 std::getline(is, line);
701 //dstream<<"got line: \""<<line<<"\""<<std::endl;
703 std::string trimmedline = trim(line);
706 if(trimmedline[0] == '#')
709 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
711 Strfnd sf(trim(line));
713 std::string name = sf.next("=");
719 std::string value = sf.next("\n");
722 dstream<<"Config name=\""<<name<<"\" value=\""
723 <<value<<"\""<<std::endl;
725 m_settings[name] = value;
731 Read configuration file
733 Returns true on success
735 bool readConfigFile(const char *filename)
737 std::ifstream is(filename);
738 if(is.good() == false)
740 dstream<<"Error opening configuration file \""
741 <<filename<<"\""<<std::endl;
745 dstream<<"Parsing configuration file: \""
746 <<filename<<"\""<<std::endl;
748 while(parseConfigObject(is));
754 Reads a configuration object from stream (usually a single line)
757 Preserves comments and empty lines.
759 Settings that were added to dst are also added to updated.
760 key of updated is setting name, value of updated is dummy.
764 bool getUpdatedConfigObject(std::istream &is,
765 core::list<std::string> &dst,
766 core::map<std::string, bool> &updated)
771 // NOTE: This function will be expanded to allow multi-line settings
773 std::getline(is, line);
775 std::string trimmedline = trim(line);
777 std::string line_end = "";
778 if(is.eof() == false)
782 if(trimmedline[0] == '#')
784 dst.push_back(line+line_end);
788 Strfnd sf(trim(line));
790 std::string name = sf.next("=");
795 dst.push_back(line+line_end);
799 std::string value = sf.next("\n");
802 if(m_settings.find(name))
804 std::string newvalue = m_settings[name];
806 if(newvalue != value)
808 dstream<<"Changing value of \""<<name<<"\" = \""
809 <<value<<"\" -> \""<<newvalue<<"\""
813 dst.push_back(name + " = " + newvalue + line_end);
815 updated[name] = true;
822 Updates configuration file
824 Returns true on success
826 bool updateConfigFile(const char *filename)
828 dstream<<"Updating configuration file: \""
829 <<filename<<"\""<<std::endl;
831 core::list<std::string> objects;
832 core::map<std::string, bool> updated;
834 // Read and modify stuff
836 std::ifstream is(filename);
837 if(is.good() == false)
839 dstream<<"Error opening configuration file"
841 <<filename<<"\""<<std::endl;
845 while(getUpdatedConfigObject(is, objects, updated));
850 std::ofstream os(filename);
851 if(os.good() == false)
853 dstream<<"Error opening configuration file"
855 <<filename<<"\""<<std::endl;
862 for(core::list<std::string>::Iterator
864 i != objects.end(); i++)
870 Write stuff that was not already in the file
872 for(core::map<std::string, std::string>::Iterator
873 i = m_settings.getIterator();
874 i.atEnd() == false; i++)
876 if(updated.find(i.getNode()->getKey()))
878 std::string name = i.getNode()->getKey();
879 std::string value = i.getNode()->getValue();
880 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
882 os<<name<<" = "<<value<<"\n";
890 NOTE: Types of allowed_options are ignored
892 returns true on success
894 bool parseCommandLine(int argc, char *argv[],
895 core::map<std::string, ValueSpec> &allowed_options)
902 std::string argname = argv[i];
903 if(argname.substr(0, 2) != "--")
905 dstream<<"Invalid command-line parameter \""
906 <<argname<<"\": --<option> expected."<<std::endl;
911 std::string name = argname.substr(2);
913 core::map<std::string, ValueSpec>::Node *n;
914 n = allowed_options.find(name);
917 dstream<<"Unknown command-line parameter \""
918 <<argname<<"\""<<std::endl;
922 ValueType type = n->getValue().type;
924 std::string value = "";
926 if(type == VALUETYPE_FLAG)
934 dstream<<"Invalid command-line parameter \""
935 <<name<<"\": missing value"<<std::endl;
943 dstream<<"Valid command-line parameter: \""
944 <<name<<"\" = \""<<value<<"\""
952 void set(std::string name, std::string value)
954 m_settings[name] = value;
957 void setDefault(std::string name, std::string value)
959 m_defaults[name] = value;
962 bool exists(std::string name)
964 return (m_settings.find(name) || m_defaults.find(name));
967 std::string get(std::string name)
969 core::map<std::string, std::string>::Node *n;
970 n = m_settings.find(name);
973 n = m_defaults.find(name);
976 throw SettingNotFoundException("Setting not found");
980 return n->getValue();
983 bool getBool(std::string name)
985 return is_yes(get(name));
988 bool getFlag(std::string name)
992 return getBool(name);
994 catch(SettingNotFoundException &e)
1001 bool getBoolAsk(std::string name, std::string question, bool def)
1003 std::string s = get(name);
1008 std::cout<<question<<" [y/N]: ";
1009 std::cin.getline(templine, 10);
1018 float getFloat(std::string name)
1021 std::istringstream vis(get(name));
1026 u16 getU16(std::string name)
1028 return stoi(get(name), 0, 65535);
1031 u16 getU16Ask(std::string name, std::string question, u16 def)
1033 std::string s = get(name);
1035 return stoi(s, 0, 65535);
1038 std::cout<<question<<" ["<<def<<"]: ";
1039 std::cin.getline(templine, 10);
1045 return stoi(s, 0, 65535);
1048 s16 getS16(std::string name)
1050 return stoi(get(name), -32768, 32767);
1053 s32 getS32(std::string name)
1055 return stoi(get(name));
1059 core::map<std::string, std::string> m_settings;
1060 core::map<std::string, std::string> m_defaults;
1064 A thread-safe texture cache.
1066 This is used so that irrlicht doesn't get called from many threads
1075 assert(m_mutex.IsInitialized());
1078 void set(std::string name, video::ITexture *texture)
1080 JMutexAutoLock lock(m_mutex);
1082 m_textures[name] = texture;
1085 video::ITexture* get(std::string name)
1087 JMutexAutoLock lock(m_mutex);
1089 core::map<std::string, video::ITexture*>::Node *n;
1090 n = m_textures.find(name);
1093 return n->getValue();
1099 core::map<std::string, video::ITexture*> m_textures;