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
27 #include "common_irrlicht.h"
30 #include "exceptions.h"
36 #include <jmutexautolock.h>
38 extern const v3s16 g_26dirs[26];
40 inline void writeU32(u8 *data, u32 i)
42 data[0] = ((i>>24)&0xff);
43 data[1] = ((i>>16)&0xff);
44 data[2] = ((i>> 8)&0xff);
45 data[3] = ((i>> 0)&0xff);
48 inline void writeU16(u8 *data, u16 i)
50 data[0] = ((i>> 8)&0xff);
51 data[1] = ((i>> 0)&0xff);
54 inline void writeU8(u8 *data, u8 i)
56 data[0] = ((i>> 0)&0xff);
59 inline u32 readU32(u8 *data)
61 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
64 inline u16 readU16(u8 *data)
66 return (data[0]<<8) | (data[1]<<0);
69 inline u8 readU8(u8 *data)
74 // Signed variants of the above
76 inline void writeS32(u8 *data, s32 i){
77 writeU32(data, (u32)i);
79 inline s32 readS32(u8 *data){
80 return (s32)readU32(data);
83 inline void writeS16(u8 *data, s16 i){
84 writeU16(data, (u16)i);
86 inline s16 readS16(u8 *data){
87 return (s16)readU16(data);
90 inline void writeV3S32(u8 *data, v3s32 p)
92 writeS32(&data[0], p.X);
93 writeS32(&data[4], p.Y);
94 writeS32(&data[8], p.Z);
97 inline v3s32 readV3S32(u8 *data)
100 p.X = readS32(&data[0]);
101 p.Y = readS32(&data[4]);
102 p.Z = readS32(&data[8]);
106 inline void writeV2S16(u8 *data, v2s16 p)
108 writeS16(&data[0], p.X);
109 writeS16(&data[2], p.Y);
112 inline v2s16 readV2S16(u8 *data)
115 p.X = readS16(&data[0]);
116 p.Y = readS16(&data[2]);
120 inline void writeV2S32(u8 *data, v2s32 p)
122 writeS32(&data[0], p.X);
123 writeS32(&data[2], p.Y);
126 inline v2s32 readV2S32(u8 *data)
129 p.X = readS32(&data[0]);
130 p.Y = readS32(&data[2]);
134 inline void writeV3S16(u8 *data, v3s16 p)
136 writeS16(&data[0], p.X);
137 writeS16(&data[2], p.Y);
138 writeS16(&data[4], p.Z);
141 inline v3s16 readV3S16(u8 *data)
144 p.X = readS16(&data[0]);
145 p.Y = readS16(&data[2]);
146 p.Z = readS16(&data[4]);
151 None of these are used at the moment
154 template <typename T>
164 SharedPtr(SharedPtr<T> &t)
168 refcount = t.refcount;
176 SharedPtr<T> & operator=(T *t)
184 SharedPtr<T> & operator=(SharedPtr<T> &t)
187 refcount = t.refcount;
200 bool operator!=(T *t)
204 bool operator==(T *t)
211 assert((*refcount) > 0);
224 template <typename T>
228 Buffer(unsigned int size)
233 Buffer(const Buffer &buffer)
235 m_size = buffer.m_size;
236 data = new T[buffer.m_size];
237 memcpy(data, buffer.data, buffer.m_size);
239 Buffer(T *t, unsigned int size)
243 memcpy(data, t, size);
249 T & operator[](unsigned int i) const
253 T * operator*() const
257 unsigned int getSize() const
266 template <typename T>
270 SharedBuffer(unsigned int size)
274 refcount = new unsigned int;
277 SharedBuffer(const SharedBuffer &buffer)
279 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
280 m_size = buffer.m_size;
282 refcount = buffer.refcount;
285 SharedBuffer & operator=(const SharedBuffer & buffer)
287 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
291 m_size = buffer.m_size;
293 refcount = buffer.refcount;
300 SharedBuffer(T *t, unsigned int size)
304 memcpy(data, t, size);
305 refcount = new unsigned int;
311 SharedBuffer(const Buffer<T> &buffer)
313 m_size = buffer.m_size;
314 data = new T[buffer.getSize()];
315 memcpy(data, *buffer, buffer.getSize());
316 refcount = new unsigned int;
323 T & operator[](unsigned int i) const
327 T * operator*() const
331 unsigned int getSize() const
338 assert((*refcount) > 0);
348 unsigned int *refcount;
351 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
353 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
358 class MutexedVariable
361 MutexedVariable(T value):
369 JMutexAutoLock lock(m_mutex);
375 JMutexAutoLock lock(m_mutex);
379 // You'll want to grab this in a SharedPtr
380 JMutexAutoLock * getLock()
382 return new JMutexAutoLock(m_mutex);
385 // You pretty surely want to grab the lock when accessing this
399 TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
410 m_time1 = m_dev->getTimer()->getRealTime();
416 u32 stop(bool quiet=false)
423 std::cout<<"Couldn't measure time for "<<m_name
424 <<": dev==NULL"<<std::endl;*/
427 u32 time2 = m_dev->getTimer()->getRealTime();
428 u32 dtime = time2 - m_time1;
431 (*m_result) += dtime;
436 std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
445 IrrlichtDevice *m_dev;
451 // Calculates the borders of a "d-radius" cube
452 inline void getFacePositions(core::list<v3s16> &list, u16 d)
456 list.push_back(v3s16(0,0,0));
462 This is an optimized sequence of coordinates.
464 list.push_back(v3s16( 0, 0, 1)); // back
465 list.push_back(v3s16(-1, 0, 0)); // left
466 list.push_back(v3s16( 1, 0, 0)); // right
467 list.push_back(v3s16( 0, 0,-1)); // front
468 list.push_back(v3s16( 0,-1, 0)); // bottom
469 list.push_back(v3s16( 0, 1, 0)); // top
471 list.push_back(v3s16(-1, 0, 1)); // back left
472 list.push_back(v3s16( 1, 0, 1)); // back right
473 list.push_back(v3s16(-1, 0,-1)); // front left
474 list.push_back(v3s16( 1, 0,-1)); // front right
475 list.push_back(v3s16(-1,-1, 0)); // bottom left
476 list.push_back(v3s16( 1,-1, 0)); // bottom right
477 list.push_back(v3s16( 0,-1, 1)); // bottom back
478 list.push_back(v3s16( 0,-1,-1)); // bottom front
479 list.push_back(v3s16(-1, 1, 0)); // top left
480 list.push_back(v3s16( 1, 1, 0)); // top right
481 list.push_back(v3s16( 0, 1, 1)); // top back
482 list.push_back(v3s16( 0, 1,-1)); // top front
484 list.push_back(v3s16(-1, 1, 1)); // top back-left
485 list.push_back(v3s16( 1, 1, 1)); // top back-right
486 list.push_back(v3s16(-1, 1,-1)); // top front-left
487 list.push_back(v3s16( 1, 1,-1)); // top front-right
488 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
489 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
490 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
491 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
496 // Take blocks in all sides, starting from y=0 and going +-y
497 for(s16 y=0; y<=d-1; y++)
499 // Left and right side, including borders
500 for(s16 z=-d; z<=d; z++)
502 list.push_back(v3s16(d,y,z));
503 list.push_back(v3s16(-d,y,z));
506 list.push_back(v3s16(d,-y,z));
507 list.push_back(v3s16(-d,-y,z));
510 // Back and front side, excluding borders
511 for(s16 x=-d+1; x<=d-1; x++)
513 list.push_back(v3s16(x,y,d));
514 list.push_back(v3s16(x,y,-d));
517 list.push_back(v3s16(x,-y,d));
518 list.push_back(v3s16(x,-y,-d));
523 // Take the bottom and top face with borders
524 // -d<x<d, y=+-d, -d<z<d
525 for(s16 x=-d; x<=d; x++)
526 for(s16 z=-d; z<=d; z++)
528 list.push_back(v3s16(x,-d,z));
529 list.push_back(v3s16(x,d,z));
533 class IndentationRaiser
536 IndentationRaiser(u16 *indentation)
538 m_indentation = indentation;
549 inline s16 getContainerPos(s16 p, s16 d)
551 return (p>=0 ? p : p-d+1) / d;
554 inline v2s16 getContainerPos(v2s16 p, s16 d)
557 getContainerPos(p.X, d),
558 getContainerPos(p.Y, d)
562 inline v3s16 getContainerPos(v3s16 p, s16 d)
565 getContainerPos(p.X, d),
566 getContainerPos(p.Y, d),
567 getContainerPos(p.Z, d)
571 inline bool isInArea(v3s16 p, s16 d)
574 p.X >= 0 && p.X < d &&
575 p.Y >= 0 && p.Y < d &&
580 inline bool isInArea(v2s16 p, s16 d)
583 p.X >= 0 && p.X < d &&
588 inline std::wstring narrow_to_wide(const std::string& mbs)
590 size_t wcl = mbs.size();
591 SharedBuffer<wchar_t> wcs(wcl+1);
592 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
597 inline std::string wide_to_narrow(const std::wstring& wcs)
599 size_t mbl = wcs.size()*4;
600 SharedBuffer<char> mbs(mbl+1);
601 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
610 See test.cpp for example cases.
611 wraps degrees to the range of -360...360
612 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
614 inline float wrapDegrees(float f)
616 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
622 // NOTE: This would be used for wrapping to 0...360
628 // 10, 0.5, -0.5, -0.5
633 inline std::string lowercase(std::string s)
635 for(size_t i=0; i<s.size(); i++)
637 if(s[i] >= 'A' && s[i] <= 'Z')
643 inline bool is_yes(std::string s)
645 s = lowercase(trim(s));
646 if(s == "y" || s == "yes" || s == "true")
651 inline s32 stoi(std::string s, s32 min, s32 max)
653 s32 i = atoi(s.c_str());
661 inline s32 stoi(std::string s)
663 return atoi(s.c_str());
674 // Returns false on EOF
675 bool parseConfigObject(std::istream &is)
680 // NOTE: This function will be expanded to allow multi-line settings
682 std::getline(is, line);
683 //dstream<<"got line: \""<<line<<"\""<<std::endl;
685 std::string trimmedline = trim(line);
688 if(trimmedline[0] == '#')
691 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
693 Strfnd sf(trim(line));
695 std::string name = sf.next("=");
701 std::string value = sf.next("\n");
704 dstream<<"Config name=\""<<name<<"\" value=\""
705 <<value<<"\""<<std::endl;
707 m_settings[name] = value;
712 // Returns true on success
713 bool readConfigFile(const char *filename)
715 std::ifstream is(filename);
716 if(is.good() == false)
718 dstream<<"Error opening configuration file: "
719 <<filename<<std::endl;
723 dstream<<"Parsing configuration file: "
724 <<filename<<std::endl;
726 while(parseConfigObject(is));
731 void set(std::string name, std::string value)
733 m_settings[name] = value;
736 std::string get(std::string name)
738 core::map<std::string, std::string>::Node *n;
739 n = m_settings.find(name);
741 throw SettingNotFoundException("Setting not found");
743 return n->getValue();
746 bool getBool(std::string name)
748 return is_yes(get(name));
752 bool getBoolAsk(std::string name, std::string question, bool def)
754 std::string s = get(name);
759 std::cout<<question<<" [y/N]: ";
760 std::cin.getline(templine, 10);
769 float getFloat(std::string name)
772 std::istringstream vis(get(name));
777 u16 getU16(std::string name)
779 return stoi(get(name), 0, 65535);
782 u16 getU16Ask(std::string name, std::string question, u16 def)
784 std::string s = get(name);
786 return stoi(s, 0, 65535);
789 std::cout<<question<<" ["<<def<<"]: ";
790 std::cin.getline(templine, 10);
796 return stoi(s, 0, 65535);
799 s16 getS16(std::string name)
801 return stoi(get(name), -32768, 32767);
804 s32 getS32(std::string name)
806 return stoi(get(name));
810 core::map<std::string, std::string> m_settings;
814 A thread-safe texture cache.
816 This is used so that irrlicht doesn't get called from many threads
825 assert(m_mutex.IsInitialized());
828 void set(std::string name, video::ITexture *texture)
830 JMutexAutoLock lock(m_mutex);
832 m_textures[name] = texture;
835 video::ITexture* get(std::string name)
837 JMutexAutoLock lock(m_mutex);
839 core::map<std::string, video::ITexture*>::Node *n;
840 n = m_textures.find(name);
843 return n->getValue();
849 core::map<std::string, video::ITexture*> m_textures;