d22e1d65131394988a0b429c569f49d136b160bb
[oweals/minetest.git] / src / utility.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #ifndef UTILITY_HEADER
25 #define UTILITY_HEADER
26
27 #include "common_irrlicht.h"
28 #include "debug.h"
29 #include "strfnd.h"
30 #include "exceptions.h"
31 #include <iostream>
32 #include <fstream>
33 #include <string>
34 #include <sstream>
35 #include <jmutex.h>
36 #include <jmutexautolock.h>
37
38 extern const v3s16 g_26dirs[26];
39
40 inline void writeU32(u8 *data, u32 i)
41 {
42         data[0] = ((i>>24)&0xff);
43         data[1] = ((i>>16)&0xff);
44         data[2] = ((i>> 8)&0xff);
45         data[3] = ((i>> 0)&0xff);
46 }
47
48 inline void writeU16(u8 *data, u16 i)
49 {
50         data[0] = ((i>> 8)&0xff);
51         data[1] = ((i>> 0)&0xff);
52 }
53
54 inline void writeU8(u8 *data, u8 i)
55 {
56         data[0] = ((i>> 0)&0xff);
57 }
58
59 inline u32 readU32(u8 *data)
60 {
61         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
62 }
63
64 inline u16 readU16(u8 *data)
65 {
66         return (data[0]<<8) | (data[1]<<0);
67 }
68
69 inline u8 readU8(u8 *data)
70 {
71         return (data[0]<<0);
72 }
73
74 // Signed variants of the above
75
76 inline void writeS32(u8 *data, s32 i){
77         writeU32(data, (u32)i);
78 }
79 inline s32 readS32(u8 *data){
80         return (s32)readU32(data);
81 }
82
83 inline void writeS16(u8 *data, s16 i){
84         writeU16(data, (u16)i);
85 }
86 inline s16 readS16(u8 *data){
87         return (s16)readU16(data);
88 }
89
90 inline void writeV3S32(u8 *data, v3s32 p)
91 {
92         writeS32(&data[0], p.X);
93         writeS32(&data[4], p.Y);
94         writeS32(&data[8], p.Z);
95 }
96
97 inline v3s32 readV3S32(u8 *data)
98 {
99         v3s32 p;
100         p.X = readS32(&data[0]);
101         p.Y = readS32(&data[4]);
102         p.Z = readS32(&data[8]);
103         return p;
104 }
105
106 inline void writeV2S16(u8 *data, v2s16 p)
107 {
108         writeS16(&data[0], p.X);
109         writeS16(&data[2], p.Y);
110 }
111
112 inline v2s16 readV2S16(u8 *data)
113 {
114         v2s16 p;
115         p.X = readS16(&data[0]);
116         p.Y = readS16(&data[2]);
117         return p;
118 }
119
120 inline void writeV2S32(u8 *data, v2s32 p)
121 {
122         writeS32(&data[0], p.X);
123         writeS32(&data[2], p.Y);
124 }
125
126 inline v2s32 readV2S32(u8 *data)
127 {
128         v2s32 p;
129         p.X = readS32(&data[0]);
130         p.Y = readS32(&data[2]);
131         return p;
132 }
133
134 inline void writeV3S16(u8 *data, v3s16 p)
135 {
136         writeS16(&data[0], p.X);
137         writeS16(&data[2], p.Y);
138         writeS16(&data[4], p.Z);
139 }
140
141 inline v3s16 readV3S16(u8 *data)
142 {
143         v3s16 p;
144         p.X = readS16(&data[0]);
145         p.Y = readS16(&data[2]);
146         p.Z = readS16(&data[4]);
147         return p;
148 }
149
150 /*
151         None of these are used at the moment
152 */
153
154 template <typename T>
155 class SharedPtr
156 {
157 public:
158         SharedPtr(T *t=NULL)
159         {
160                 refcount = new int;
161                 *refcount = 1;
162                 ptr = t;
163         }
164         SharedPtr(SharedPtr<T> &t)
165         {
166                 //*this = t;
167                 drop();
168                 refcount = t.refcount;
169                 (*refcount)++;
170                 ptr = t.ptr;
171         }
172         ~SharedPtr()
173         {
174                 drop();
175         }
176         SharedPtr<T> & operator=(T *t)
177         {
178                 drop();
179                 refcount = new int;
180                 *refcount = 1;
181                 ptr = t;
182                 return *this;
183         }
184         SharedPtr<T> & operator=(SharedPtr<T> &t)
185         {
186                 drop();
187                 refcount = t.refcount;
188                 (*refcount)++;
189                 ptr = t.ptr;
190                 return *this;
191         }
192         T* operator->()
193         {
194                 return ptr;
195         }
196         T & operator*()
197         {
198                 return *ptr;
199         }
200         bool operator!=(T *t)
201         {
202                 return ptr != t;
203         }
204         bool operator==(T *t)
205         {
206                 return ptr == t;
207         }
208 private:
209         void drop()
210         {
211                 assert((*refcount) > 0);
212                 (*refcount)--;
213                 if(*refcount == 0)
214                 {
215                         delete refcount;
216                         if(ptr != NULL)
217                                 delete ptr;
218                 }
219         }
220         T *ptr;
221         int *refcount;
222 };
223
224 template <typename T>
225 class Buffer
226 {
227 public:
228         Buffer(unsigned int size)
229         {
230                 m_size = size;
231                 data = new T[size];
232         }
233         Buffer(const Buffer &buffer)
234         {
235                 m_size = buffer.m_size;
236                 data = new T[buffer.m_size];
237                 memcpy(data, buffer.data, buffer.m_size);
238         }
239         Buffer(T *t, unsigned int size)
240         {
241                 m_size = size;
242                 data = new T[size];
243                 memcpy(data, t, size);
244         }
245         ~Buffer()
246         {
247                 delete[] data;
248         }
249         T & operator[](unsigned int i) const
250         {
251                 return data[i];
252         }
253         T * operator*() const
254         {
255                 return data;
256         }
257         unsigned int getSize() const
258         {
259                 return m_size;
260         }
261 private:
262         T *data;
263         unsigned int m_size;
264 };
265
266 template <typename T>
267 class SharedBuffer
268 {
269 public:
270         SharedBuffer(unsigned int size)
271         {
272                 m_size = size;
273                 data = new T[size];
274                 refcount = new unsigned int;
275                 (*refcount) = 1;
276         }
277         SharedBuffer(const SharedBuffer &buffer)
278         {
279                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
280                 m_size = buffer.m_size;
281                 data = buffer.data;
282                 refcount = buffer.refcount;
283                 (*refcount)++;
284         }
285         SharedBuffer & operator=(const SharedBuffer & buffer)
286         {
287                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
288                 if(this == &buffer)
289                         return *this;
290                 drop();
291                 m_size = buffer.m_size;
292                 data = buffer.data;
293                 refcount = buffer.refcount;
294                 (*refcount)++;
295                 return *this;
296         }
297         /*
298                 Copies whole buffer
299         */
300         SharedBuffer(T *t, unsigned int size)
301         {
302                 m_size = size;
303                 data = new T[size];
304                 memcpy(data, t, size);
305                 refcount = new unsigned int;
306                 (*refcount) = 1;
307         }
308         /*
309                 Copies whole buffer
310         */
311         SharedBuffer(const Buffer<T> &buffer)
312         {
313                 m_size = buffer.m_size;
314                 data = new T[buffer.getSize()];
315                 memcpy(data, *buffer, buffer.getSize());
316                 refcount = new unsigned int;
317                 (*refcount) = 1;
318         }
319         ~SharedBuffer()
320         {
321                 drop();
322         }
323         T & operator[](unsigned int i) const
324         {
325                 return data[i];
326         }
327         T * operator*() const
328         {
329                 return data;
330         }
331         unsigned int getSize() const
332         {
333                 return m_size;
334         }
335 private:
336         void drop()
337         {
338                 assert((*refcount) > 0);
339                 (*refcount)--;
340                 if(*refcount == 0)
341                 {
342                         delete[] data;
343                         delete refcount;
344                 }
345         }
346         T *data;
347         unsigned int m_size;
348         unsigned int *refcount;
349 };
350
351 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
352 {
353         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
354         return b;
355 }
356
357 template<typename T>
358 class MutexedVariable
359 {
360 public:
361         MutexedVariable(T value):
362                 m_value(value)
363         {
364                 m_mutex.Init();
365         }
366
367         T get()
368         {
369                 JMutexAutoLock lock(m_mutex);
370                 return m_value;
371         }
372
373         void set(T value)
374         {
375                 JMutexAutoLock lock(m_mutex);
376                 m_value = value;
377         }
378         
379         // You'll want to grab this in a SharedPtr
380         JMutexAutoLock * getLock()
381         {
382                 return new JMutexAutoLock(m_mutex);
383         }
384         
385         // You pretty surely want to grab the lock when accessing this
386         T m_value;
387
388 private:
389         JMutex m_mutex;
390 };
391
392 /*
393         TimeTaker
394 */
395
396 class TimeTaker
397 {
398 public:
399         TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
400         {
401                 m_name = name;
402                 m_dev = dev;
403                 m_result = result;
404                 m_running = true;
405                 if(dev == NULL)
406                 {
407                         m_time1 = 0;
408                         return;
409                 }
410                 m_time1 = m_dev->getTimer()->getRealTime();
411         }
412         ~TimeTaker()
413         {
414                 stop();
415         }
416         u32 stop(bool quiet=false)
417         {
418                 if(m_running)
419                 {
420                         if(m_dev == NULL)
421                         {
422                                 /*if(quiet == false)
423                                         std::cout<<"Couldn't measure time for "<<m_name
424                                                         <<": dev==NULL"<<std::endl;*/
425                                 return 0;
426                         }
427                         u32 time2 = m_dev->getTimer()->getRealTime();
428                         u32 dtime = time2 - m_time1;
429                         if(m_result != NULL)
430                         {
431                                 (*m_result) += dtime;
432                         }
433                         else
434                         {
435                                 if(quiet == false)
436                                         std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
437                         }
438                         m_running = false;
439                         return dtime;
440                 }
441                 return 0;
442         }
443 private:
444         const char *m_name;
445         IrrlichtDevice *m_dev;
446         u32 m_time1;
447         bool m_running;
448         u32 *m_result;
449 };
450
451 // Calculates the borders of a "d-radius" cube
452 inline void getFacePositions(core::list<v3s16> &list, u16 d)
453 {
454         if(d == 0)
455         {
456                 list.push_back(v3s16(0,0,0));
457                 return;
458         }
459         if(d == 1)
460         {
461                 /*
462                         This is an optimized sequence of coordinates.
463                 */
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
470                 // 6
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
483                 // 18
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
492                 // 26
493                 return;
494         }
495
496         // Take blocks in all sides, starting from y=0 and going +-y
497         for(s16 y=0; y<=d-1; y++)
498         {
499                 // Left and right side, including borders
500                 for(s16 z=-d; z<=d; z++)
501                 {
502                         list.push_back(v3s16(d,y,z));
503                         list.push_back(v3s16(-d,y,z));
504                         if(y != 0)
505                         {
506                                 list.push_back(v3s16(d,-y,z));
507                                 list.push_back(v3s16(-d,-y,z));
508                         }
509                 }
510                 // Back and front side, excluding borders
511                 for(s16 x=-d+1; x<=d-1; x++)
512                 {
513                         list.push_back(v3s16(x,y,d));
514                         list.push_back(v3s16(x,y,-d));
515                         if(y != 0)
516                         {
517                                 list.push_back(v3s16(x,-y,d));
518                                 list.push_back(v3s16(x,-y,-d));
519                         }
520                 }
521         }
522
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++)
527         {
528                 list.push_back(v3s16(x,-d,z));
529                 list.push_back(v3s16(x,d,z));
530         }
531 }
532
533 class IndentationRaiser
534 {
535 public:
536         IndentationRaiser(u16 *indentation)
537         {
538                 m_indentation = indentation;
539                 (*m_indentation)++;
540         }
541         ~IndentationRaiser()
542         {
543                 (*m_indentation)--;
544         }
545 private:
546         u16 *m_indentation;
547 };
548
549 inline s16 getContainerPos(s16 p, s16 d)
550 {
551         return (p>=0 ? p : p-d+1) / d;
552 }
553
554 inline v2s16 getContainerPos(v2s16 p, s16 d)
555 {
556         return v2s16(
557                 getContainerPos(p.X, d),
558                 getContainerPos(p.Y, d)
559         );
560 }
561
562 inline v3s16 getContainerPos(v3s16 p, s16 d)
563 {
564         return v3s16(
565                 getContainerPos(p.X, d),
566                 getContainerPos(p.Y, d),
567                 getContainerPos(p.Z, d)
568         );
569 }
570
571 inline bool isInArea(v3s16 p, s16 d)
572 {
573         return (
574                 p.X >= 0 && p.X < d &&
575                 p.Y >= 0 && p.Y < d &&
576                 p.Z >= 0 && p.Z < d
577         );
578 }
579
580 inline bool isInArea(v2s16 p, s16 d)
581 {
582         return (
583                 p.X >= 0 && p.X < d &&
584                 p.Y >= 0 && p.Y < d
585         );
586 }
587
588 inline std::wstring narrow_to_wide(const std::string& mbs)
589 {
590         size_t wcl = mbs.size();
591         SharedBuffer<wchar_t> wcs(wcl+1);
592         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
593         wcs[l] = 0;
594         return *wcs;
595 }
596
597 inline std::string wide_to_narrow(const std::wstring& wcs)
598 {
599         size_t mbl = wcs.size()*4;
600         SharedBuffer<char> mbs(mbl+1);
601         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
602         if((int)l == -1)
603                 mbs[0] = 0;
604         else
605                 mbs[l] = 0;
606         return *mbs;
607 }
608
609 /*
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.
613 */
614 inline float wrapDegrees(float f)
615 {
616         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
617         // This results in
618         // 10, 720, -1, -361
619         int i = floor(f);
620         // 0, 2, 0, -1
621         int l = i / 360;
622         // NOTE: This would be used for wrapping to 0...360
623         // 0, 2, -1, -2
624         /*if(i < 0)
625                 l -= 1;*/
626         // 0, 720, 0, -360
627         int k = l * 360;
628         // 10, 0.5, -0.5, -0.5
629         f -= float(k);
630         return f;
631 }
632
633 inline std::string lowercase(std::string s)
634 {
635         for(size_t i=0; i<s.size(); i++)
636         {
637                 if(s[i] >= 'A' && s[i] <= 'Z')
638                         s[i] -= 'A' - 'a';
639         }
640         return s;
641 }
642
643 inline bool is_yes(std::string s)
644 {
645         s = lowercase(trim(s));
646         if(s == "y" || s == "yes" || s == "true")
647                 return true;
648         return false;
649 }
650
651 inline s32 stoi(std::string s, s32 min, s32 max)
652 {
653         s32 i = atoi(s.c_str());
654         if(i < min)
655                 i = min;
656         if(i > max)
657                 i = max;
658         return i;
659 }
660
661 inline s32 stoi(std::string s)
662 {
663         return atoi(s.c_str());
664 }
665
666 /*
667         Config stuff
668 */
669
670 class Settings
671 {
672 public:
673
674         // Returns false on EOF
675         bool parseConfigObject(std::istream &is)
676         {
677                 if(is.eof())
678                         return false;
679                 
680                 // NOTE: This function will be expanded to allow multi-line settings
681                 std::string line;
682                 std::getline(is, line);
683                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
684
685                 std::string trimmedline = trim(line);
686                 
687                 // Ignore comments
688                 if(trimmedline[0] == '#')
689                         return true;
690
691                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
692
693                 Strfnd sf(trim(line));
694
695                 std::string name = sf.next("=");
696                 name = trim(name);
697
698                 if(name == "")
699                         return true;
700                 
701                 std::string value = sf.next("\n");
702                 value = trim(value);
703
704                 dstream<<"Config name=\""<<name<<"\" value=\""
705                                 <<value<<"\""<<std::endl;
706                 
707                 m_settings[name] = value;
708                 
709                 return true;
710         }
711
712         // Returns true on success
713         bool readConfigFile(const char *filename)
714         {
715                 std::ifstream is(filename);
716                 if(is.good() == false)
717                 {
718                         dstream<<"Error opening configuration file: "
719                                         <<filename<<std::endl;
720                         return false;
721                 }
722
723                 dstream<<"Parsing configuration file: "
724                                 <<filename<<std::endl;
725                                 
726                 while(parseConfigObject(is));
727                 
728                 return true;
729         }
730
731         void set(std::string name, std::string value)
732         {
733                 m_settings[name] = value;
734         }
735
736         std::string get(std::string name)
737         {
738                 core::map<std::string, std::string>::Node *n;
739                 n = m_settings.find(name);
740                 if(n == NULL)
741                         throw SettingNotFoundException("Setting not found");
742
743                 return n->getValue();
744         }
745
746         bool getBool(std::string name)
747         {
748                 return is_yes(get(name));
749         }
750         
751         // Asks if empty
752         bool getBoolAsk(std::string name, std::string question, bool def)
753         {
754                 std::string s = get(name);
755                 if(s != "")
756                         return is_yes(s);
757                 
758                 char templine[10];
759                 std::cout<<question<<" [y/N]: ";
760                 std::cin.getline(templine, 10);
761                 s = templine;
762
763                 if(s == "")
764                         return def;
765
766                 return is_yes(s);
767         }
768
769         float getFloat(std::string name)
770         {
771                 float f;
772                 std::istringstream vis(get(name));
773                 vis>>f;
774                 return f;
775         }
776
777         u16 getU16(std::string name)
778         {
779                 return stoi(get(name), 0, 65535);
780         }
781
782         u16 getU16Ask(std::string name, std::string question, u16 def)
783         {
784                 std::string s = get(name);
785                 if(s != "")
786                         return stoi(s, 0, 65535);
787                 
788                 char templine[10];
789                 std::cout<<question<<" ["<<def<<"]: ";
790                 std::cin.getline(templine, 10);
791                 s = templine;
792
793                 if(s == "")
794                         return def;
795
796                 return stoi(s, 0, 65535);
797         }
798
799         s16 getS16(std::string name)
800         {
801                 return stoi(get(name), -32768, 32767);
802         }
803
804         s32 getS32(std::string name)
805         {
806                 return stoi(get(name));
807         }
808
809 private:
810         core::map<std::string, std::string> m_settings;
811 };
812
813 /*
814         A thread-safe texture cache.
815
816         This is used so that irrlicht doesn't get called from many threads
817 */
818
819 class TextureCache
820 {
821 public:
822         TextureCache()
823         {
824                 m_mutex.Init();
825                 assert(m_mutex.IsInitialized());
826         }
827         
828         void set(std::string name, video::ITexture *texture)
829         {
830                 JMutexAutoLock lock(m_mutex);
831
832                 m_textures[name] = texture;
833         }
834         
835         video::ITexture* get(std::string name)
836         {
837                 JMutexAutoLock lock(m_mutex);
838
839                 core::map<std::string, video::ITexture*>::Node *n;
840                 n = m_textures.find(name);
841
842                 if(n != NULL)
843                         return n->getValue();
844
845                 return NULL;
846         }
847
848 private:
849         core::map<std::string, video::ITexture*> m_textures;
850         JMutex m_mutex;
851 };
852
853 #endif
854