Browse Source

Merge branch 'dev' of https://github.com/oxygine/oxygine-framework into dev

dmuratshin 9 years ago
parent
commit
2da02eaa7c
43 changed files with 538 additions and 299 deletions
  1. BIN
      examples/Demo/data/images/batterfly.png
  2. 1 1
      examples/Demo/data/xmls/res.xml
  3. 1 1
      examples/Demo/src/TestDrag.h
  4. 5 6
      examples/Demo/src/TestManageRes.h
  5. 5 14
      examples/Demo/src/TestPolygon.h
  6. 1 1
      examples/HelloWorld/src/entry_point.cpp
  7. 5 5
      examples/HelloWorld/src/example.cpp
  8. 9 2
      oxygine/src/Actor.cpp
  9. 2 0
      oxygine/src/Actor.h
  10. 2 2
      oxygine/src/ClipRectActor.cpp
  11. 7 1
      oxygine/src/DebugActor.cpp
  12. 1 0
      oxygine/src/DebugActor.h
  13. 8 16
      oxygine/src/Font.cpp
  14. 22 3
      oxygine/src/Font.h
  15. 12 3
      oxygine/src/MemoryTexture.cpp
  16. 4 0
      oxygine/src/MemoryTexture.h
  17. 2 0
      oxygine/src/ProgressBar.cpp
  18. 4 0
      oxygine/src/STDRenderer.cpp
  19. 19 3
      oxygine/src/TextField.cpp
  20. 4 1
      oxygine/src/TextField.h
  21. 1 1
      oxygine/src/TweenAlphaFade.h
  22. 2 1
      oxygine/src/core/Renderer.h
  23. 4 2
      oxygine/src/core/emscripten/HttpRequestEmscriptenTask.cpp
  24. 1 1
      oxygine/src/core/gl/ShaderProgramGL.cpp
  25. 140 98
      oxygine/src/core/oxygine.cpp
  26. 10 0
      oxygine/src/core/oxygine.h
  27. 4 4
      oxygine/src/core/s3e/MyHttp.cpp
  28. 16 0
      oxygine/src/math/Rect.h
  29. 2 1
      oxygine/src/oxygine_include.h
  30. 10 12
      oxygine/src/res/CreateResourceContext.h
  31. 9 0
      oxygine/src/res/ResAnim.cpp
  32. 1 0
      oxygine/src/res/ResAnim.h
  33. 50 26
      oxygine/src/res/ResAtlas.cpp
  34. 3 2
      oxygine/src/res/ResFontBM.h
  35. 3 3
      oxygine/src/res/ResStarlingAtlas.cpp
  36. 70 63
      oxygine/src/res/Resources.cpp
  37. 44 16
      oxygine/src/res/Resources.h
  38. 4 4
      oxygine/src/text_utils/Node.cpp
  39. 2 2
      oxygine/src/text_utils/Node.h
  40. 9 3
      oxygine/src/utils/ImageUtils.cpp
  41. 26 0
      oxygine/src/utils/stringUtils.cpp
  42. 12 0
      oxygine/src/utils/stringUtils.h
  43. 1 1
      readme/Android.txt

BIN
examples/Demo/data/images/batterfly.png


+ 1 - 1
examples/Demo/data/xmls/res.xml

@@ -42,7 +42,7 @@
 		<image file="score_table.png"/>
 		<image file="score_table.png"/>
 	</atlas>
 	</atlas>
 
 
-	<atlas> 
+	<atlas clamp2edge="false"> 
 		<image file="tiled.png" trim="false" extend="false"/>
 		<image file="tiled.png" trim="false" extend="false"/>
 	</atlas>	
 	</atlas>	
 	
 	

+ 1 - 1
examples/Demo/src/TestDrag.h

@@ -39,7 +39,7 @@ public:
             float angle = scalar::randFloat(0, (float)MATH_PI * 2);
             float angle = scalar::randFloat(0, (float)MATH_PI * 2);
             sprite->setRotation(angle);
             sprite->setRotation(angle);
             sprite->addTween(Actor::TweenRotation(MATH_PI * 2 + angle), 30000, -1);
             sprite->addTween(Actor::TweenRotation(MATH_PI * 2 + angle), 30000, -1);
-            sprite->setScale(scalar::randFloat(1.0f, 1.5f));
+            sprite->setScale(scalar::randFloat(0.8f, 1.2f));
             sprite->setAnchor(0.5f, 0.5f);
             sprite->setAnchor(0.5f, 0.5f);
 
 
             sprite->addEventListener(TouchEvent::TOUCH_DOWN, CLOSURE(this, &DragTest::onMouseDown));
             sprite->addEventListener(TouchEvent::TOUCH_DOWN, CLOSURE(this, &DragTest::onMouseDown));

+ 5 - 6
examples/Demo/src/TestManageRes.h

@@ -19,9 +19,12 @@ public:
 #endif
 #endif
 
 
 
 
-        for (int i = 0; i < resources.getCount(); ++i)
+        Resources::resources items;
+        resources.collect(items);
+
+        for (size_t i = 0; i < items.size(); ++i)
         {
         {
-            ResAnim* ra = dynamic_cast<ResAnim*>(resources.get(i));
+            ResAnim* ra = dynamic_cast<ResAnim*>(items[i].get());
             if (!ra)
             if (!ra)
                 continue;
                 continue;
             if (ra->getName().find("_") != string::npos)
             if (ra->getName().find("_") != string::npos)
@@ -38,10 +41,6 @@ public:
                 sprite->setPosition(0, 0);
                 sprite->setPosition(0, 0);
                 sprite->setPriority(-1);
                 sprite->setPriority(-1);
             }
             }
-            else
-            {
-                //sprite->addEventHandler(new DragHandler);
-            }
         }
         }
 
 
         spTextField text = new TextField;
         spTextField text = new TextField;

+ 5 - 14
examples/Demo/src/TestPolygon.h

@@ -17,25 +17,16 @@ public:
         poly->addTween(Actor::TweenRotation(MATH_PI * 2), 16000, -1);
         poly->addTween(Actor::TweenRotation(MATH_PI * 2), 16000, -1);
         poly->setPosition(content->getSize() / 2);
         poly->setPosition(content->getSize() / 2);
 
 
-        ResAnim* rs = resources.getResAnim("tiled");
-
-
         //ResAnim "tiled" has only single frame and uses own separate atlas texture
         //ResAnim "tiled" has only single frame and uses own separate atlas texture
-        //also it should have options trim=extend=false
+        //it should have options trim=extend=false
+        //and atlas with option clamp2edge=false to allow tiling
         /*
         /*
-        <atlas>
-            <image file="tiled.png" trim="false" extend="false"/>
+        <atlas clamp2edge="false">
+        <image file="tiled.png" trim="false" extend="false"/>
         </atlas>
         </atlas>
         */
         */
 
 
-        //need access to texture
-        AnimationFrame frame = rs->getFrame(0);
-        spNativeTexture texture = frame.getDiffuse().base;
-
-        //by default all textures has mode "clamp to edge"
-        //disable it and allow tiling
-        texture->setClamp2Edge(false);
-
+        ResAnim* rs = resources.getResAnim("tiled");
         poly->setResAnim(rs);
         poly->setResAnim(rs);
 
 
         update(_num);
         update(_num);

+ 1 - 1
examples/HelloWorld/src/entry_point.cpp

@@ -66,7 +66,7 @@ void run()
     Point size = core::getDisplaySize();
     Point size = core::getDisplaySize();
     getStage()->setSize(size);
     getStage()->setSize(size);
 
 
-    //DebugActor is a helper actor node. It shows FPS, memory usage and other useful stuff
+    //DebugActor is a helper actor node. It shows FPS, memory usage and other useful stuff, also it initializes some default resourcess
     DebugActor::show();
     DebugActor::show();
 
 
     //initialize this example stuff. see example.cpp
     //initialize this example stuff. see example.cpp

+ 5 - 5
examples/HelloWorld/src/example.cpp

@@ -16,7 +16,7 @@ public:
 
 
     MainActor()
     MainActor()
     {
     {
-        //create simple Sprite
+        //create button Sprite
         spSprite button = new Sprite();
         spSprite button = new Sprite();
 
 
         //setup it:
         //setup it:
@@ -27,7 +27,7 @@ public:
         Vector2 pos = getStage()->getSize() / 2 - button->getSize() / 2;
         Vector2 pos = getStage()->getSize() / 2 - button->getSize() / 2;
         button->setPosition(pos);
         button->setPosition(pos);
 
 
-        //handle click to button
+        //register  click handler to button
         EventCallback cb = CLOSURE(this, &MainActor::buttonClicked);
         EventCallback cb = CLOSURE(this, &MainActor::buttonClicked);
         button->addEventListener(TouchEvent::CLICK, cb);
         button->addEventListener(TouchEvent::CLICK, cb);
 
 
@@ -42,11 +42,9 @@ public:
 
 
         //attach button as child to current actor
         //attach button as child to current actor
         addChild(button);
         addChild(button);
-
         _button = button;
         _button = button;
 
 
 
 
-        //second part
 
 
         //create TextField Actor
         //create TextField Actor
         spTextField text = new TextField();
         spTextField text = new TextField();
@@ -125,6 +123,8 @@ public:
 };
 };
 //declare spMainActor as intrusive_ptr holder of MainActor
 //declare spMainActor as intrusive_ptr holder of MainActor
 typedef oxygine::intrusive_ptr<MainActor> spMainActor;
 typedef oxygine::intrusive_ptr<MainActor> spMainActor;
+//you could use DECLARE_SMART preprocessor definition it does the same:
+//DECLARE_SMART(MainActor, spMainActor)
 
 
 void example_preinit() {}
 void example_preinit() {}
 
 
@@ -136,7 +136,7 @@ void example_init()
 
 
 
 
     //lets create our client code simple actor
     //lets create our client code simple actor
-    //spMainActor was defined above as smart intrusive pointer (read more: http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/intrusive_ptr.html)
+    //spMainActor was defined above as smart intrusive pointer (read more: http://www.boost.org/doc/libs/1_60_0/libs/smart_ptr/intrusive_ptr.html)
     spMainActor actor = new MainActor;
     spMainActor actor = new MainActor;
 
 
     //and add it to Stage as child
     //and add it to Stage as child

+ 9 - 2
oxygine/src/Actor.cpp

@@ -412,6 +412,11 @@ namespace oxygine
         _flags |= flag_transformDirty | flag_transformInvertDirty;
         _flags |= flag_transformDirty | flag_transformInvertDirty;
     }
     }
 
 
+    void Actor::setAnchorInPixels(float x, float y)
+    {
+        setAnchorInPixels(Vector2(x, y));
+    }
+
     void Actor::setPosition(const Vector2& pos)
     void Actor::setPosition(const Vector2& pos)
     {
     {
         if (_pos == pos)
         if (_pos == pos)
@@ -661,6 +666,8 @@ namespace oxygine
 
 
         _transform = tr;
         _transform = tr;
         _flags &= ~flag_transformDirty;
         _flags &= ~flag_transformDirty;
+
+        const_cast<Actor*>(this)->transformUpdated();
     }
     }
 
 
     bool Actor::isOn(const Vector2& localPosition)
     bool Actor::isOn(const Vector2& localPosition)
@@ -1310,7 +1317,7 @@ namespace oxygine
     {
     {
         Transform t;
         Transform t;
         t.identity();
         t.identity();
-        while (child != parent)
+        while (child && child != parent)
         {
         {
             t = t * child->getTransform();
             t = t * child->getTransform();
             child = child->getParent();
             child = child->getParent();
@@ -1323,7 +1330,7 @@ namespace oxygine
     {
     {
         Transform t;
         Transform t;
         t.identity();
         t.identity();
-        while (child.get() != parent)
+        while (child && (child.get() != parent))
         {
         {
             t = t * child->getTransform();
             t = t * child->getTransform();
             child = child->getParent();
             child = child->getParent();

+ 2 - 0
oxygine/src/Actor.h

@@ -157,6 +157,7 @@ namespace oxygine
         void setAnchor(const Vector2& anchor);
         void setAnchor(const Vector2& anchor);
         void setAnchor(float ax, float ay);
         void setAnchor(float ax, float ay);
         void setAnchorInPixels(const Vector2& anchor);
         void setAnchorInPixels(const Vector2& anchor);
+        void setAnchorInPixels(float x, float y);
         void setPosition(const Vector2& pos);
         void setPosition(const Vector2& pos);
         void setPosition(float x, float y);
         void setPosition(float x, float y);
         void setX(float x);
         void setX(float x);
@@ -314,6 +315,7 @@ namespace oxygine
         void removedFromStage();
         void removedFromStage();
         virtual void onAdded2Stage() {}
         virtual void onAdded2Stage() {}
         virtual void onRemovedFromStage() {}
         virtual void onRemovedFromStage() {}
+        virtual void transformUpdated() {}
 
 
 
 
         typedef intrusive_list<spActor> children;
         typedef intrusive_list<spActor> children;

+ 2 - 2
oxygine/src/ClipRectActor.cpp

@@ -46,11 +46,11 @@ namespace oxygine
     {
     {
         _Actor::serialize(data);
         _Actor::serialize(data);
         pugi::xml_node node = data->node;
         pugi::xml_node node = data->node;
-        node.set_name("Sprite");
+        node.set_name("ClipRectActor");
     }
     }
 
 
     void ClipRectActor::deserialize(const deserializedata* data)
     void ClipRectActor::deserialize(const deserializedata* data)
     {
     {
         _Actor::deserialize(data);
         _Actor::deserialize(data);
     }
     }
-}
+}

+ 7 - 1
oxygine/src/DebugActor.cpp

@@ -68,6 +68,12 @@ namespace oxygine
         getStage()->addChild(DebugActor::instance);
         getStage()->addChild(DebugActor::instance);
     }
     }
 
 
+    void DebugActor::hide()
+    {
+        if (DebugActor::instance)
+            DebugActor::instance->detach();
+    }
+
     void DebugActor::release()
     void DebugActor::release()
     {
     {
         instance = 0;
         instance = 0;
@@ -282,7 +288,7 @@ namespace oxygine
         s << "update=" << getStage()->_statUpdate << "ms ";
         s << "update=" << getStage()->_statUpdate << "ms ";
         s << "render=" << getStage()->_statRender << "ms ";
         s << "render=" << getStage()->_statRender << "ms ";
         s << "textures=" << NativeTexture::created << " ";
         s << "textures=" << NativeTexture::created << " ";
-        s << "\nlisteners=" << getStage()->getListenersCount() << "";
+        //s << "\nlisteners=" << getStage()->getListenersCount() << "";
 
 
         if (!_debugText.empty())
         if (!_debugText.empty())
         {
         {

+ 1 - 0
oxygine/src/DebugActor.h

@@ -22,6 +22,7 @@ namespace oxygine
         static Resources* resSystem;
         static Resources* resSystem;
         static void initialize();
         static void initialize();
         static void show();
         static void show();
+        static void hide();
         static void release();
         static void release();
         static std::string getDefaultName() { return "debug_actor"; }
         static std::string getDefaultName() { return "debug_actor"; }
 
 

+ 8 - 16
oxygine/src/Font.cpp

@@ -32,12 +32,13 @@ namespace oxygine
         _size = realSize;
         _size = realSize;
         _baselineDistance = baselineDistance;
         _baselineDistance = baselineDistance;
         _lineHeight = lineHeight;
         _lineHeight = lineHeight;
-        _glyphs.reserve(200);
+        //_glyphs.reserve(200);
     }
     }
 
 
     void Font::addGlyph(const glyph& gl)
     void Font::addGlyph(const glyph& gl)
     {
     {
-        _glyphs.push_back(gl);
+        _glyphs.insert(gl);
+        //_glyphs.push_back(gl);
     }
     }
 
 
     bool glyphFindPred(const glyph& g, int code)
     bool glyphFindPred(const glyph& g, int code)
@@ -50,19 +51,14 @@ namespace oxygine
         return ob1.ch < ob2.ch;
         return ob1.ch < ob2.ch;
     }
     }
 
 
-    void Font::sortGlyphs()
-    {
-        std::sort(_glyphs.begin(), _glyphs.end(), glyphsComparePred);
-    }
-
     const glyph* Font::findGlyph(int code) const
     const glyph* Font::findGlyph(int code) const
     {
     {
-        glyphs::const_iterator it = std::lower_bound(_glyphs.begin(), _glyphs.end(), code, glyphFindPred);
+        glyph g;
+        g.ch = code;
+        glyphs::const_iterator it = _glyphs.find(g);
         if (it != _glyphs.end())
         if (it != _glyphs.end())
         {
         {
-            const glyph& g = *it;
-            if (g.ch == code)
-                return &g;
+            return &(*it);
         }
         }
 
 
         return 0;
         return 0;
@@ -78,11 +74,7 @@ namespace oxygine
         Font* fn = const_cast<Font*>(this);
         Font* fn = const_cast<Font*>(this);
         if (fn->loadGlyph(code, gl))
         if (fn->loadGlyph(code, gl))
         {
         {
-            glyphs::iterator it = std::lower_bound(fn->_glyphs.begin(), fn->_glyphs.end(), code, glyphFindPred);
-            fn->_glyphs.insert(it, gl);
-
-            //fn->addGlyph(gl);
-            //fn->sortGlyphs();
+            fn->_glyphs.insert(gl);
             g = findGlyph(code);
             g = findGlyph(code);
             OX_ASSERT(g);
             OX_ASSERT(g);
         }
         }

+ 22 - 3
oxygine/src/Font.h

@@ -2,7 +2,11 @@
 #include "oxygine_include.h"
 #include "oxygine_include.h"
 #include "core/Object.h"
 #include "core/Object.h"
 #include "math/Rect.h"
 #include "math/Rect.h"
-
+#ifdef __S3E__
+#include <set>
+#else
+#include <unordered_set>
+#endif
 namespace oxygine
 namespace oxygine
 {
 {
     DECLARE_SMART(NativeTexture, spNativeTexture);
     DECLARE_SMART(NativeTexture, spNativeTexture);
@@ -23,6 +27,17 @@ namespace oxygine
         short advance_y;
         short advance_y;
 
 
         spNativeTexture texture;
         spNativeTexture texture;
+
+        bool operator == (const glyph& r) const {return ch == r.ch;}
+        bool operator < (const glyph& r) const { return ch < r.ch; }
+    };
+
+    struct GlyphHasher
+    {
+        std::size_t operator()(const glyph& k) const
+        {
+            return std::hash<int>()(k.ch);
+        }
     };
     };
 
 
     class Font: public ObjectBase
     class Font: public ObjectBase
@@ -34,7 +49,7 @@ namespace oxygine
         void init(const char* name, int size, int baselineDistance, int lineHeight);
         void init(const char* name, int size, int baselineDistance, int lineHeight);
 
 
         void addGlyph(const glyph& g);
         void addGlyph(const glyph& g);
-        void sortGlyphs();
+        void sortGlyphs() {}
 
 
         void setScale(float scale) { _scale = scale; }
         void setScale(float scale) { _scale = scale; }
 
 
@@ -49,7 +64,11 @@ namespace oxygine
 
 
         virtual bool loadGlyph(int code, glyph&) { return false; }
         virtual bool loadGlyph(int code, glyph&) { return false; }
 
 
-        typedef std::vector<glyph> glyphs;
+#ifdef __S3E__
+        typedef std::set<glyph> glyphs;
+#else
+        typedef std::unordered_set<glyph, GlyphHasher> glyphs;
+#endif
         glyphs _glyphs;
         glyphs _glyphs;
 
 
         float _scale;
         float _scale;

+ 12 - 3
oxygine/src/MemoryTexture.cpp

@@ -28,9 +28,6 @@ extern "C"
 namespace oxygine
 namespace oxygine
 {
 {
 
 
-    typedef bool (*cbLoadImageFromBuffer)(MemoryTexture& mt, void* data, int nSize, bool premultiplied, TextureFormat format);
-
-
 
 
     bool loadImageNotSupported(MemoryTexture& mt, void* data, int nSize, bool premultiplied, TextureFormat format)
     bool loadImageNotSupported(MemoryTexture& mt, void* data, int nSize, bool premultiplied, TextureFormat format)
     {
     {
@@ -494,6 +491,18 @@ namespace oxygine
 #endif
 #endif
 
 
 
 
+
+
+    void setJpegLoader(cbLoadImageFromBuffer cb)
+    {
+        _loadJpegImage = cb;
+    }
+
+    void setPngLoader(cbLoadImageFromBuffer cb)
+    {
+        _loadPngImage = cb;
+    }
+
     bool loadPngImage(MemoryTexture& mt, void* pData, int nDatalen, bool premultiplied, TextureFormat format)
     bool loadPngImage(MemoryTexture& mt, void* pData, int nDatalen, bool premultiplied, TextureFormat format)
     {
     {
         bool s = _loadPngImage(mt, pData, nDatalen, premultiplied, format);
         bool s = _loadPngImage(mt, pData, nDatalen, premultiplied, format);

+ 4 - 0
oxygine/src/MemoryTexture.h

@@ -57,4 +57,8 @@ namespace oxygine
         size_t _offset;//buffer offset
         size_t _offset;//buffer offset
         std::vector<unsigned char> _buffer;
         std::vector<unsigned char> _buffer;
     };
     };
+
+    typedef bool (*cbLoadImageFromBuffer)(MemoryTexture& mt, void* data, int nSize, bool premultiplied, TextureFormat format);
+    void setJpegLoader(cbLoadImageFromBuffer);
+    void setPngLoader(cbLoadImageFromBuffer);
 }
 }

+ 2 - 0
oxygine/src/ProgressBar.cpp

@@ -401,5 +401,7 @@ namespace oxygine
         _Sprite::deserialize(data);
         _Sprite::deserialize(data);
         _direction = (direction)data->node.attribute("direction").as_int();
         _direction = (direction)data->node.attribute("direction").as_int();
         _progress = data->node.attribute("progress").as_float(1.0f);
         _progress = data->node.attribute("progress").as_float(1.0f);
+
+        _update();
     }
     }
 }
 }

+ 4 - 0
oxygine/src/STDRenderer.cpp

@@ -413,6 +413,10 @@ namespace oxygine
                 case blend_multiply:
                 case blend_multiply:
                     _driver->setBlendFunc(IVideoDriver::BT_DST_COLOR, IVideoDriver::BT_ONE_MINUS_SRC_ALPHA);
                     _driver->setBlendFunc(IVideoDriver::BT_DST_COLOR, IVideoDriver::BT_ONE_MINUS_SRC_ALPHA);
                     break;
                     break;
+                case blend_inverse:
+                    _driver->setBlendFunc(IVideoDriver::BT_ONE_MINUS_DST_COLOR, IVideoDriver::BT_ZERO);
+                    break;
+
                 //case blend_sub:
                 //case blend_sub:
                 //_driver->setBlendFunc(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE);
                 //_driver->setBlendFunc(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE);
                 //glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
                 //glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);

+ 19 - 3
oxygine/src/TextField.cpp

@@ -85,6 +85,12 @@ namespace oxygine
         needRebuild();
         needRebuild();
     }
     }
 
 
+    void TextField::setKerning(int kerning)
+    {
+        _style.kerning = kerning;
+        needRebuild();
+    }
+
     void TextField::setFontSize2Scale(int scale2size)
     void TextField::setFontSize2Scale(int scale2size)
     {
     {
         _style.fontSize2Scale = scale2size;
         _style.fontSize2Scale = scale2size;
@@ -195,7 +201,12 @@ namespace oxygine
         return _style.breakLongWords;
         return _style.breakLongWords;
     }
     }
 
 
-    const text::Symbol* TextField::getSymbolAt(int pos) const
+    int TextField::getKerning() const
+    {
+        return _style.kerning;
+    }
+
+    text::Symbol* TextField::getSymbolAt(int pos) const
     {
     {
         return const_cast<TextField*>(this)->getRootNode()->getSymbol(pos);
         return const_cast<TextField*>(this)->getRootNode()->getSymbol(pos);
     }
     }
@@ -347,6 +358,7 @@ namespace oxygine
             node.append_attribute("text").set_value(_text.c_str());
             node.append_attribute("text").set_value(_text.c_str());
         setAttr(node, "fontsize2scale", _style.fontSize2Scale, def.fontSize2Scale);
         setAttr(node, "fontsize2scale", _style.fontSize2Scale, def.fontSize2Scale);
         setAttr(node, "linesOffset", _style.linesOffset, def.linesOffset);
         setAttr(node, "linesOffset", _style.linesOffset, def.linesOffset);
+        setAttr(node, "kerning", _style.kerning, def.kerning);
         setAttr(node, "valign", _style.vAlign, def.vAlign);
         setAttr(node, "valign", _style.vAlign, def.vAlign);
         setAttr(node, "halign", _style.hAlign, def.hAlign);
         setAttr(node, "halign", _style.hAlign, def.hAlign);
         setAttr(node, "multiline", _style.multiline, def.multiline);
         setAttr(node, "multiline", _style.multiline, def.multiline);
@@ -369,9 +381,13 @@ namespace oxygine
         _style.breakLongWords = node.attribute("breakLongWords").as_bool(def.breakLongWords);
         _style.breakLongWords = node.attribute("breakLongWords").as_bool(def.breakLongWords);
         _style.fontSize2Scale = node.attribute("fontsize2scale").as_int(def.fontSize2Scale);
         _style.fontSize2Scale = node.attribute("fontsize2scale").as_int(def.fontSize2Scale);
         _style.linesOffset = node.attribute("linesOffset").as_int(def.linesOffset);
         _style.linesOffset = node.attribute("linesOffset").as_int(def.linesOffset);
+        _style.kerning = node.attribute("kerning").as_int(def.kerning);
         const char* fnt = node.attribute("font").as_string(0);
         const char* fnt = node.attribute("font").as_string(0);
-        if (fnt)
-            _style.font = data->factory->getResFont(fnt)->getFont();
+        if (fnt && *fnt)
+        {
+            ResFont* font = data->factory->getResFont(fnt);
+            _style.font = font->getFont();
+        }
 
 
         needRebuild();
         needRebuild();
         setText(node.attribute("text").as_string());
         setText(node.attribute("text").as_string());

+ 4 - 1
oxygine/src/TextField.h

@@ -33,11 +33,12 @@ namespace oxygine
         const Font*                 getFont() const;
         const Font*                 getFont() const;
         int                         getFontSize2Scale() const;
         int                         getFontSize2Scale() const;
         int                         getLinesOffset() const;
         int                         getLinesOffset() const;
+        int                         getKerning() const;
         TextStyle::VerticalAlign    getVAlign() const;
         TextStyle::VerticalAlign    getVAlign() const;
         TextStyle::HorizontalAlign  getHAlign() const;
         TextStyle::HorizontalAlign  getHAlign() const;
         bool                        getMultiline() const;
         bool                        getMultiline() const;
         bool                        getBreakLongWords() const;
         bool                        getBreakLongWords() const;
-        const text::Symbol*         getSymbolAt(int pos) const;
+        text::Symbol*               getSymbolAt(int pos) const;
 
 
         /**Overwrites TextStyle Vertical align*/
         /**Overwrites TextStyle Vertical align*/
         void setVAlign(TextStyle::VerticalAlign align);
         void setVAlign(TextStyle::VerticalAlign align);
@@ -50,6 +51,8 @@ namespace oxygine
         void setBreakLongWords(bool val);
         void setBreakLongWords(bool val);
         /**Overwrites TextStyle linesOffset*/
         /**Overwrites TextStyle linesOffset*/
         void setLinesOffset(int offset);
         void setLinesOffset(int offset);
+        /**Overwrites TextStyle kerning*/
+        void setKerning(int kerning);
         /**Overwrites TextStyle scale2Size.*/
         /**Overwrites TextStyle scale2Size.*/
         void setFontSize2Scale(int scale2size);
         void setFontSize2Scale(int scale2size);
         /**Overwrites TextStyle font.*/
         /**Overwrites TextStyle font.*/

+ 1 - 1
oxygine/src/TweenAlphaFade.h

@@ -22,7 +22,7 @@ namespace oxygine
         enum options
         enum options
         {
         {
             opt_singleR2T = 1,
             opt_singleR2T = 1,
-            opt_fullscreen = 1,
+            opt_fullscreen = 1 << 1,
         };
         };
 
 
         int _options;
         int _options;

+ 2 - 1
oxygine/src/core/Renderer.h

@@ -25,6 +25,7 @@ namespace oxygine
         blend_alpha,
         blend_alpha,
         blend_add,
         blend_add,
         blend_multiply,
         blend_multiply,
+        blend_inverse,
     };
     };
 
 
 
 
@@ -228,4 +229,4 @@ namespace oxygine
 
 
     /**Returns View matrix where Left Top corner is (0,0), and right bottom is (w,h)*/
     /**Returns View matrix where Left Top corner is (0,0), and right bottom is (w,h)*/
     Matrix makeViewMatrix(int w, int h, bool flipU = false);
     Matrix makeViewMatrix(int w, int h, bool flipU = false);
-}
+}

+ 4 - 2
oxygine/src/core/emscripten/HttpRequestEmscriptenTask.cpp

@@ -43,9 +43,11 @@ namespace oxygine
         addRef();
         addRef();
 
 
         log::messageln("HttpRequestEmscriptenTask::_run %s", _url.c_str());
         log::messageln("HttpRequestEmscriptenTask::_run %s", _url.c_str());
-        _postData.push_back(0);
+        const char* method = _postData.empty() ? "GET" : "POST";
+        if (!_postData.empty())
+            _postData.push_back(0);
 
 
-        emscripten_async_wget2_data(_url.c_str(), _postData.empty() ? "GET" : "POST", (char*)&_postData.front(), this, false, onload, onerror, onprogress);
+        emscripten_async_wget2_data(_url.c_str(), method, (char*)&_postData.front(), this, false, onload, onerror, onprogress);
     }
     }
     //int  emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
     //int  emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
     //void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, void (*onload)(void*, void*, unsigned), void (*onerror)(void*, int, const char*), void (*onprogress)(void*, int, int));
     //void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, void (*onload)(void*, void*, unsigned), void (*onerror)(void*, int, const char*), void (*onprogress)(void*, int, int));

+ 1 - 1
oxygine/src/core/gl/ShaderProgramGL.cpp

@@ -94,7 +94,7 @@ namespace oxygine
                 "#define highp\n";
                 "#define highp\n";
 
 
             *ptr = nonGLES;
             *ptr = nonGLES;
-			ptr++;
+            ptr++;
         }
         }
 #endif
 #endif
 
 

+ 140 - 98
oxygine/src/core/oxygine.cpp

@@ -107,6 +107,7 @@ namespace oxygine
     static core::init_desc desc;
     static core::init_desc desc;
     Point _qtFixedSize(0, 0);
     Point _qtFixedSize(0, 0);
 
 
+    spEventDispatcher _dispatcher;
 
 
 #ifdef __S3E__
 #ifdef __S3E__
 
 
@@ -238,6 +239,11 @@ namespace oxygine
         {
         {
             Input::instance.__removeFromDebugList();
             Input::instance.__removeFromDebugList();
 
 
+
+            if (!_dispatcher)
+                _dispatcher = new EventDispatcher;
+
+
             log::messageln("initialize oxygine");
             log::messageln("initialize oxygine");
             if (desc_ptr)
             if (desc_ptr)
                 desc = *desc_ptr;
                 desc = *desc_ptr;
@@ -318,9 +324,19 @@ namespace oxygine
             SDL_Init(SDL_INIT_VIDEO);
             SDL_Init(SDL_INIT_VIDEO);
 
 
 
 
-            SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
-            SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
-            SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+            if (desc.mode24bpp)
+            {
+                SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+                SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+                SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+            }
+            else
+            {
+                SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
+                SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
+                SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+            }
+
             SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
             SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
             SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
             SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
             SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
             SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
@@ -353,6 +369,11 @@ namespace oxygine
             if (desc.fullscreen)
             if (desc.fullscreen)
                 flags |= SDL_WINDOW_FULLSCREEN;
                 flags |= SDL_WINDOW_FULLSCREEN;
 
 
+            {
+                Event ev(EVENT_PRECREATEWINDOW);
+                _dispatcher->dispatchEvent(&ev);
+            }
+
             log::messageln("creating window %d %d", desc.w, desc.h);
             log::messageln("creating window %d %d", desc.w, desc.h);
 
 
             _window = SDL_CreateWindow(desc.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, desc.w, desc.h, flags);
             _window = SDL_CreateWindow(desc.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, desc.w, desc.h, flags);
@@ -383,6 +404,9 @@ namespace oxygine
 
 
         void init2()
         void init2()
         {
         {
+            if (!_dispatcher)
+                _dispatcher = new EventDispatcher;
+
 #ifdef OXYGINE_EDITOR
 #ifdef OXYGINE_EDITOR
             setlocale(LC_ALL, "POSIX");
             setlocale(LC_ALL, "POSIX");
 #endif
 #endif
@@ -413,6 +437,8 @@ namespace oxygine
 
 
             CHECKGL();
             CHECKGL();
 
 
+
+
             STDRenderer::initialize();
             STDRenderer::initialize();
 
 
             Resources::registerResourceType(ResAtlas::create, "atlas");
             Resources::registerResourceType(ResAtlas::create, "atlas");
@@ -451,6 +477,11 @@ namespace oxygine
             return focus;
             return focus;
         }
         }
 
 
+        spEventDispatcher getDispatcher()
+        {
+            return _dispatcher;
+        }
+
 
 
 #if OXYGINE_SDL
 #if OXYGINE_SDL
         SDL_GLContext getGLContext()
         SDL_GLContext getGLContext()
@@ -555,122 +586,131 @@ namespace oxygine
             if (!stage)
             if (!stage)
                 stage = getStage();
                 stage = getStage();
 
 
-            Event ev(Input::event_platform);
+            //deprecated
+            {
+                Event ev(Input::event_platform);
+                ev.userData = &event;
+                Input::instance.dispatchEvent(&ev);
+            }
+
+
+            Event ev(EVENT_SYSTEM);
             ev.userData = &event;
             ev.userData = &event;
-            Input::instance.dispatchEvent(&ev);
+            _dispatcher->dispatchEvent(&ev);
 
 
-            switch (event.type)
-            {
-                case SDL_QUIT:
-                    done = true;
-                    break;
-                case SDL_WINDOWEVENT:
+            if (!ev.stopsPropagation)
+                switch (event.type)
                 {
                 {
-                    /*
-                    if (event.window.event == SDL_WINDOWEVENT_ENTER)
-                    active = false;
-                    if (event.window.event == SDL_WINDOWEVENT_LEAVE)
-                    active = true;
-                    */
-
-                    if (event.window.event == SDL_WINDOWEVENT_MINIMIZED)
+                    case SDL_QUIT:
+                        done = true;
+                        break;
+                    case SDL_WINDOWEVENT:
+                    {
+                        /*
+                        if (event.window.event == SDL_WINDOWEVENT_ENTER)
                         active = false;
                         active = false;
-                    if (event.window.event == SDL_WINDOWEVENT_RESTORED)
+                        if (event.window.event == SDL_WINDOWEVENT_LEAVE)
                         active = true;
                         active = true;
-
-                    bool newFocus = focus;
-                    if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
-                        newFocus = false;
-                    if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
-                        newFocus = true;
-                    if (focus != newFocus)
-                    {
-                        focus = newFocus;
+                        */
+
+                        if (event.window.event == SDL_WINDOWEVENT_MINIMIZED)
+                            active = false;
+                        if (event.window.event == SDL_WINDOWEVENT_RESTORED)
+                            active = true;
+
+                        bool newFocus = focus;
+                        if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
+                            newFocus = false;
+                        if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
+                            newFocus = true;
+                        if (focus != newFocus)
+                        {
+                            focus = newFocus;
 #if HANDLE_FOCUS_LOST
 #if HANDLE_FOCUS_LOST
 
 
-                        if (focus)
-                            focusAcquired();
+                            if (focus)
+                                focusAcquired();
 
 
-                        log::messageln("focus: %d", (int)focus);
-                        Event ev(focus ? Stage::ACTIVATE : Stage::DEACTIVATE);
-                        if (stage)
-                            stage->dispatchEvent(&ev);
+                            log::messageln("focus: %d", (int)focus);
+                            Event ev(focus ? Stage::ACTIVATE : Stage::DEACTIVATE);
+                            if (stage)
+                                stage->dispatchEvent(&ev);
 
 
-                        if (!focus)
-                            focusLost();
+                            if (!focus)
+                                focusLost();
 #endif
 #endif
+                        }
+                        //log::messageln("SDL_SYSWMEVENT %d", (int)event.window.event);
+                        break;
                     }
                     }
-                    //log::messageln("SDL_SYSWMEVENT %d", (int)event.window.event);
-                    break;
-                }
-                case SDL_MOUSEWHEEL:
-                    input->sendPointerWheelEvent(stage, event.wheel.y, &input->_pointerMouse);
-                    break;
-                case SDL_KEYDOWN:
-                {
-                    KeyEvent ev(KeyEvent::KEY_DOWN, &event.key);
-                    stage->dispatchEvent(&ev);
-                } break;
-                case SDL_KEYUP:
-                {
-                    KeyEvent ev(KeyEvent::KEY_UP, &event.key);
-                    stage->dispatchEvent(&ev);
-                } break;
-
-                case SDL_MOUSEMOTION:
-                    if (!_useTouchAPI)
-                        input->sendPointerMotionEvent(stage, (float)event.motion.x, (float)event.motion.y, 1.0f, &input->_pointerMouse);
-                    break;
-                case SDL_MOUSEBUTTONDOWN:
-                case SDL_MOUSEBUTTONUP:
-                {
-                    if (!_useTouchAPI)
+                    case SDL_MOUSEWHEEL:
+                        input->sendPointerWheelEvent(stage, event.wheel.y, &input->_pointerMouse);
+                        break;
+                    case SDL_KEYDOWN:
+                    {
+                        KeyEvent ev(KeyEvent::KEY_DOWN, &event.key);
+                        stage->dispatchEvent(&ev);
+                    } break;
+                    case SDL_KEYUP:
+                    {
+                        KeyEvent ev(KeyEvent::KEY_UP, &event.key);
+                        stage->dispatchEvent(&ev);
+                    } break;
+
+                    case SDL_MOUSEMOTION:
+                        if (!_useTouchAPI)
+                            input->sendPointerMotionEvent(stage, (float)event.motion.x, (float)event.motion.y, 1.0f, &input->_pointerMouse);
+                        break;
+                    case SDL_MOUSEBUTTONDOWN:
+                    case SDL_MOUSEBUTTONUP:
                     {
                     {
-                        MouseButton b = MouseButton_Left;
-                        switch (event.button.button)
+                        if (!_useTouchAPI)
                         {
                         {
-                            case 1: b = MouseButton_Left; break;
-                            case 2: b = MouseButton_Middle; break;
-                            case 3: b = MouseButton_Right; break;
+                            MouseButton b = MouseButton_Left;
+                            switch (event.button.button)
+                            {
+                                case 1: b = MouseButton_Left; break;
+                                case 2: b = MouseButton_Middle; break;
+                                case 3: b = MouseButton_Right; break;
+                            }
+
+                            input->sendPointerButtonEvent(stage, b, (float)event.button.x, (float)event.button.y, 1.0f,
+                                                          event.type == SDL_MOUSEBUTTONDOWN ? TouchEvent::TOUCH_DOWN : TouchEvent::TOUCH_UP, &input->_pointerMouse);
                         }
                         }
-
-                        input->sendPointerButtonEvent(stage, b, (float)event.button.x, (float)event.button.y, 1.0f,
-                                                      event.type == SDL_MOUSEBUTTONDOWN ? TouchEvent::TOUCH_DOWN : TouchEvent::TOUCH_UP, &input->_pointerMouse);
                     }
                     }
-                }
-                break;
-                case SDL_FINGERMOTION:
-                {
-                    if (_useTouchAPI)
+                    break;
+                    case SDL_FINGERMOTION:
                     {
                     {
-                        //log::messageln("SDL_FINGERMOTION");
-                        Vector2 pos = convertTouch(event);
-                        PointerState* ps = input->getTouchByID((int)event.tfinger.fingerId);
-                        if (ps)
-                            input->sendPointerMotionEvent(stage,
-                                                          pos.x, pos.y, event.tfinger.pressure, ps);
+                        if (_useTouchAPI)
+                        {
+                            //log::messageln("SDL_FINGERMOTION");
+                            Vector2 pos = convertTouch(event);
+                            PointerState* ps = input->getTouchByID((int)event.tfinger.fingerId);
+                            if (ps)
+                                input->sendPointerMotionEvent(stage,
+                                                              pos.x, pos.y, event.tfinger.pressure, ps);
+                        }
                     }
                     }
-                }
 
 
-                break;
-                case SDL_FINGERDOWN:
-                case SDL_FINGERUP:
-                {
-                    if (_useTouchAPI)
+                    break;
+                    case SDL_FINGERDOWN:
+                    case SDL_FINGERUP:
                     {
                     {
-                        //log::messageln("SDL_FINGER");
-                        Vector2 pos = convertTouch(event);
-                        PointerState* ps = input->getTouchByID((int)event.tfinger.fingerId);
-                        if (ps)
-                            input->sendPointerButtonEvent(stage,
-                                                          MouseButton_Touch,
-                                                          pos.x, pos.y, event.tfinger.pressure,
-                                                          event.type == SDL_FINGERDOWN ? TouchEvent::TOUCH_DOWN : TouchEvent::TOUCH_UP,
-                                                          ps);
+                        if (_useTouchAPI)
+                        {
+                            //log::messageln("SDL_FINGER");
+                            Vector2 pos = convertTouch(event);
+                            PointerState* ps = input->getTouchByID((int)event.tfinger.fingerId);
+                            if (ps)
+                                input->sendPointerButtonEvent(stage,
+                                                              MouseButton_Touch,
+                                                              pos.x, pos.y, event.tfinger.pressure,
+                                                              event.type == SDL_FINGERDOWN ? TouchEvent::TOUCH_DOWN : TouchEvent::TOUCH_UP,
+                                                              ps);
+                        }
                     }
                     }
+                    break;
                 }
                 }
-                break;
-            }
 
 
         }
         }
 #endif
 #endif
@@ -750,6 +790,8 @@ namespace oxygine
             SDL_DestroyWindow(_window);
             SDL_DestroyWindow(_window);
             SDL_Quit();
             SDL_Quit();
 #endif
 #endif
+
+            _dispatcher = 0;
         }
         }
 
 
         void execute(const char* str)
         void execute(const char* str)

+ 10 - 0
oxygine/src/core/oxygine.h

@@ -1,5 +1,6 @@
 #pragma once
 #pragma once
 #include "oxygine_include.h"
 #include "oxygine_include.h"
+#include "../EventDispatcher.h"
 #include "math/Vector2.h"
 #include "math/Vector2.h"
 #include <string>
 #include <string>
 
 
@@ -107,9 +108,18 @@ namespace oxygine
         bool isActive();
         bool isActive();
         bool hasFocus();
         bool hasFocus();
 
 
+
 #ifdef OXYGINE_SDL
 #ifdef OXYGINE_SDL
         SDL_GLContext   getGLContext();
         SDL_GLContext   getGLContext();
         SDL_Window*     getWindow();
         SDL_Window*     getWindow();
 #endif
 #endif
+
+        enum
+        {
+            EVENT_SYSTEM = sysEventID('c', 'S', 'y'), //events from SDL
+            EVENT_PRECREATEWINDOW = sysEventID('c', 'P', 'W'),//dispatched before creating window/context
+        };
+
+        spEventDispatcher getDispatcher();
     }
     }
 }
 }

+ 4 - 4
oxygine/src/core/s3e/MyHttp.cpp

@@ -87,7 +87,7 @@ void MyHttp::get(const string& url)
     _http = new CIwHTTP;
     _http = new CIwHTTP;
     //_http->SetRequestHeader("Content-type", "application/x-www-form-urlencoded");
     //_http->SetRequestHeader("Content-type", "application/x-www-form-urlencoded");
 
 
-    if (!isNetworkAvaible())
+    if (!isNetworkAvailable())
     {
     {
         //it is too dangerous call onError from there
         //it is too dangerous call onError from there
         //do it at next update
         //do it at next update
@@ -116,7 +116,7 @@ void MyHttp::post(const string& url, const char* data, int size)
     _http = new CIwHTTP;
     _http = new CIwHTTP;
     _http->SetRequestHeader("Content-type", "application/x-www-form-urlencoded");
     _http->SetRequestHeader("Content-type", "application/x-www-form-urlencoded");
 
 
-    if (!isNetworkAvaible())
+    if (!isNetworkAvailable())
     {
     {
         //it is too dangerous call onError from there
         //it is too dangerous call onError from there
         //do it at next update
         //do it at next update
@@ -298,7 +298,7 @@ public:
 
 
 void makeSingleHttpAsyncGetRequest(const char* url)
 void makeSingleHttpAsyncGetRequest(const char* url)
 {
 {
-    if (!isNetworkAvaible())
+    if (!isNetworkAvailable())
         return;
         return;
 
 
     SingleHttpAsyncRequest* r = new SingleHttpAsyncRequest;
     SingleHttpAsyncRequest* r = new SingleHttpAsyncRequest;
@@ -307,7 +307,7 @@ void makeSingleHttpAsyncGetRequest(const char* url)
 
 
 void makeSingleHttpAsyncPostRequest(const char* url, const char* data, int size)
 void makeSingleHttpAsyncPostRequest(const char* url, const char* data, int size)
 {
 {
-    if (!isNetworkAvaible())
+    if (!isNetworkAvailable())
         return;
         return;
 
 
     SingleHttpAsyncRequest* r = new SingleHttpAsyncRequest;
     SingleHttpAsyncRequest* r = new SingleHttpAsyncRequest;

+ 16 - 0
oxygine/src/math/Rect.h

@@ -2,6 +2,7 @@
 #include "oxygine_include.h"
 #include "oxygine_include.h"
 #include "Vector2.h"
 #include "Vector2.h"
 #include <algorithm>
 #include <algorithm>
+#include <limits>
 
 
 namespace oxygine
 namespace oxygine
 {
 {
@@ -16,6 +17,15 @@ namespace oxygine
         RectT(const point2& Pos, const point2& Size): pos(Pos), size(Size) {}
         RectT(const point2& Pos, const point2& Size): pos(Pos), size(Size) {}
         RectT(T x, T y, T w, T h): pos(x, y), size(w, h) {}
         RectT(T x, T y, T w, T h): pos(x, y), size(w, h) {}
 
 
+        static const RectT invalidated()
+        {
+            return RectT(
+                       std::numeric_limits<T>::max() / 2,
+                       std::numeric_limits<T>::max() / 2,
+                       -std::numeric_limits<T>::max(),
+                       -std::numeric_limits<T>::max());
+        }
+
         bool operator == (const RectT& r) const
         bool operator == (const RectT& r) const
         {
         {
             return r.pos == pos && r.size == size;
             return r.pos == pos && r.size == size;
@@ -79,6 +89,12 @@ namespace oxygine
             size.y = std::max(rbA.y, rbB.y) - pos.y;
             size.y = std::max(rbA.y, rbB.y) - pos.y;
         }
         }
 
 
+        void unite(const point2& p)
+        {
+            RectT r(p, point2(0, 0));
+            unite(r);
+        }
+
         point2 getCenter() const {return pos + size / 2;}
         point2 getCenter() const {return pos + size / 2;}
         point2 getSize() const {return size;}
         point2 getSize() const {return size;}
         point2 getLeftTop() const {return pos;}
         point2 getLeftTop() const {return pos;}

+ 2 - 1
oxygine/src/oxygine_include.h

@@ -30,6 +30,7 @@
 #   endif // DEBUG  
 #   endif // DEBUG  
 #elif OXYGINE_EDITOR
 #elif OXYGINE_EDITOR
 #   define OXYGINE_FILESYSTEM_USE_STDIO 1
 #   define OXYGINE_FILESYSTEM_USE_STDIO 1
+#   include <qglobal.h>
 #else
 #else
 #   define OXYGINE_SDL 1
 #   define OXYGINE_SDL 1
 #   ifdef _WIN32
 #   ifdef _WIN32
@@ -73,7 +74,7 @@ namespace oxygine { namespace log { void error(const char* format, ...); } }
 
 
 //assert without log::error
 //assert without log::error
 #ifdef OXYGINE_QT
 #ifdef OXYGINE_QT
-#   define OX_ASSERT_NL(x) {assert(x);}
+#   define OX_ASSERT_NL(x) {Q_ASSERT(x);}
 #elif EMSCRIPTEN
 #elif EMSCRIPTEN
 #   define OX_ASSERT_NL(x)
 #   define OX_ASSERT_NL(x)
 #else
 #else

+ 10 - 12
oxygine/src/res/CreateResourceContext.h

@@ -6,15 +6,17 @@
 
 
 namespace oxygine
 namespace oxygine
 {
 {
-
     class Resources;
     class Resources;
-    /**internal class*/
-
 
 
+    /**internal class*/
     class XmlWalker
     class XmlWalker
     {
     {
     public:
     public:
-        XmlWalker(const std::string* xmlFolder, const std::string& path, float scaleFactor, bool load, bool alpha, pugi::xml_node xml, pugi::xml_node meta);
+        XmlWalker(const std::string* xmlFolder,
+                  const std::string& path,
+                  float scaleFactor,
+                  bool load, bool alpha,
+                  pugi::xml_node xml, pugi::xml_node meta);
 
 
         bool empty() const {return _root.empty();}
         bool empty() const {return _root.empty();}
 
 
@@ -55,26 +57,22 @@ namespace oxygine
         bool _alphaHitTest;
         bool _alphaHitTest;
     };
     };
 
 
+    class ResourcesLoadOptions;
+
     class CreateResourceContext//todo rename
     class CreateResourceContext//todo rename
     {
     {
     public:
     public:
-        CreateResourceContext(): resources(0), xml_name(0), prebuilt_folder(0),
+        CreateResourceContext() : resources(0), xml_name(0), prebuilt_folder(0), options(0),
             walker(0, "", 1.0f, true, false, pugi::xml_node(), pugi::xml_node())
             walker(0, "", 1.0f, true, false, pugi::xml_node(), pugi::xml_node())
         {
         {
-
         }
         }
 
 
         Resources* resources;
         Resources* resources;
-        //float scale_factor;
-
         XmlWalker walker;
         XmlWalker walker;
 
 
-        //pugi::xml_node node;
-        //pugi::xml_node meta;
-
         const std::string* xml_name;
         const std::string* xml_name;
-        //const string *folder;
         const std::string* prebuilt_folder;
         const std::string* prebuilt_folder;
+        const ResourcesLoadOptions* options;
     };
     };
 
 
     DECLARE_SMART(MemoryTexture, spMemoryTexture);
     DECLARE_SMART(MemoryTexture, spMemoryTexture);

+ 9 - 0
oxygine/src/res/ResAnim.cpp

@@ -52,6 +52,15 @@ namespace oxygine
         init(frames, columns, scaleFactor);
         init(frames, columns, scaleFactor);
     }
     }
 
 
+    void ResAnim::init(const std::string& file, int columns, int rows, float scaleFactor)
+    {
+        file::buffer bf;
+        file::read(file.c_str(), bf);
+        MemoryTexture mt;
+        mt.init(bf, true);
+        init(&mt, columns, rows, scaleFactor);
+    }
+
     void ResAnim::init(MemoryTexture* original, int columns, int rows, float scaleFactor)
     void ResAnim::init(MemoryTexture* original, int columns, int rows, float scaleFactor)
     {
     {
         _scaleFactor = scaleFactor;
         _scaleFactor = scaleFactor;

+ 1 - 0
oxygine/src/res/ResAnim.h

@@ -20,6 +20,7 @@ namespace oxygine
         ResAnim(Resource* atlas = 0);
         ResAnim(Resource* atlas = 0);
         ~ResAnim();
         ~ResAnim();
 
 
+        void init(const std::string& file, int columns = 1, int rows = 1, float scaleFactor = 1.0f);
         void init(MemoryTexture* original, int columns = 1, int rows = 1, float scaleFactor = 1.0f);
         void init(MemoryTexture* original, int columns = 1, int rows = 1, float scaleFactor = 1.0f);
         void init(animationFrames& frames, int columns, float scaleFactor = 1.0f, float appliedScale = 1.0f);
         void init(animationFrames& frames, int columns, float scaleFactor = 1.0f, float appliedScale = 1.0f);
         /**creates animation frames from NativeTexture*/
         /**creates animation frames from NativeTexture*/

+ 50 - 26
oxygine/src/res/ResAtlas.cpp

@@ -11,6 +11,7 @@
 #include "core/Mem2Native.h"
 #include "core/Mem2Native.h"
 #include "core/VideoDriver.h"
 #include "core/VideoDriver.h"
 #include <stdint.h>
 #include <stdint.h>
+#include "utils/stringUtils.h"
 
 
 extern "C"
 extern "C"
 {
 {
@@ -37,7 +38,7 @@ namespace oxygine
     };
     };
 
 
 
 
-    void apply_atlas(atlas_data& ad, bool linear)
+    void apply_atlas(atlas_data& ad, bool linear, bool clamp2edge)
     {
     {
         if (!ad.texture)
         if (!ad.texture)
             return;
             return;
@@ -51,11 +52,21 @@ namespace oxygine
         mt.init(ad.mt.lock().getRect(Rect(0, 0, w, h)));
         mt.init(ad.mt.lock().getRect(Rect(0, 0, w, h)));
 
 
         ImageData image_data = mt.lock();
         ImageData image_data = mt.lock();
+
+#if 0
+        static int n = 0;
+        n++;
+        char name[255];
+        safe_sprintf(name, "test%d.tga", n);
+        saveImage(image_data, name);
+#endif
+
         ad.texture->init(image_data, false);
         ad.texture->init(image_data, false);
         ad.mt.unlock();
         ad.mt.unlock();
 
 
         ad.texture->apply();
         ad.texture->apply();
         ad.texture->setLinearFilter(linear);
         ad.texture->setLinearFilter(linear);
+        ad.texture->setClamp2Edge(clamp2edge);
     }
     }
 
 
     void next_atlas(int w, int h, TextureFormat tf, atlas_data& ad, const char* name)
     void next_atlas(int w, int h, TextureFormat tf, atlas_data& ad, const char* name)
@@ -79,7 +90,7 @@ namespace oxygine
         _hook = hook;
         _hook = hook;
     }
     }
 
 
-    void load_texture_internal(const std::string& file, spNativeTexture nt, bool linearFilter, LoadResourcesContext* load_context)
+    void load_texture_internal(const std::string& file, spNativeTexture nt, bool linearFilter, bool clamp2edge, LoadResourcesContext* load_context)
     {
     {
         ImageData im;
         ImageData im;
         spMemoryTexture mt = new MemoryTexture;
         spMemoryTexture mt = new MemoryTexture;
@@ -96,10 +107,11 @@ namespace oxygine
         opt.src = mt;
         opt.src = mt;
         opt.dest = nt;
         opt.dest = nt;
         opt.linearFilter = linearFilter;
         opt.linearFilter = linearFilter;
+        opt.clamp2edge = clamp2edge;
         load_context->createTexture(opt);
         load_context->createTexture(opt);
     }
     }
 
 
-    void load_texture(const std::string& file, spNativeTexture nt, bool linearFilter, LoadResourcesContext* load_context)
+    void load_texture(const std::string& file, spNativeTexture nt, bool linearFilter, bool clamp2edge, LoadResourcesContext* load_context)
     {
     {
         if (_hook)
         if (_hook)
         {
         {
@@ -107,7 +119,7 @@ namespace oxygine
             return;
             return;
         }
         }
 
 
-        load_texture_internal(file, nt, linearFilter, load_context);
+        load_texture_internal(file, nt, linearFilter, clamp2edge, load_context);
     }
     }
 
 
 
 
@@ -154,9 +166,8 @@ namespace oxygine
             ra = rs;
             ra = rs;
         }
         }
 
 
-        context.resources->add(ra);
-
         ra->setName(_Resource::extractID(context.walker.getNode(), "", std::string("!atlas:") + *context.xml_name));
         ra->setName(_Resource::extractID(context.walker.getNode(), "", std::string("!atlas:") + *context.xml_name));
+        context.resources->add(ra);
         setNode(ra, context.walker.getNode());
         setNode(ra, context.walker.getNode());
 
 
         return ra;
         return ra;
@@ -195,14 +206,14 @@ namespace oxygine
             atlas& atl = *i;
             atlas& atl = *i;
             if (atl.base.get() == texture)
             if (atl.base.get() == texture)
             {
             {
-                load_texture(atl.base_path, atl.base, _linearFilter , &RestoreResourcesContext::instance);
+                load_texture(atl.base_path, atl.base, _linearFilter, _clamp2edge, &RestoreResourcesContext::instance);
                 atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
                 atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
                 break;
                 break;
             }
             }
 
 
             if (atl.alpha.get() == texture)
             if (atl.alpha.get() == texture)
             {
             {
-                load_texture(atl.alpha_path, atl.alpha, _linearFilter, &RestoreResourcesContext::instance);
+                load_texture(atl.alpha_path, atl.alpha, _linearFilter, _clamp2edge, &RestoreResourcesContext::instance);
                 atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
                 atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
                 break;
                 break;
             }
             }
@@ -217,12 +228,12 @@ namespace oxygine
             if (!load_context->isNeedProceed(atl.base))
             if (!load_context->isNeedProceed(atl.base))
                 continue;
                 continue;
 
 
-            load_texture(atl.base_path, atl.base, _linearFilter, load_context);
+            load_texture(atl.base_path, atl.base, _linearFilter, _clamp2edge, load_context);
             atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
             atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
 
 
             if (atl.alpha)
             if (atl.alpha)
             {
             {
-                load_texture(atl.alpha_path, atl.alpha, _linearFilter, load_context);
+                load_texture(atl.alpha_path, atl.alpha, _linearFilter, _clamp2edge, load_context);
                 atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
                 atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
             }
             }
         }
         }
@@ -323,7 +334,7 @@ namespace oxygine
                 pd.getPixel(srcLine, p);
                 pd.getPixel(srcLine, p);
 
 
 
 
-                if (p.a > 10)
+                if (p.a > 5)
                 {
                 {
                     hasAlpha = true;
                     hasAlpha = true;
 
 
@@ -515,29 +526,42 @@ namespace oxygine
                         bool s = ad.atlas.add(&ad.mt, src, dest, offset);
                         bool s = ad.atlas.add(&ad.mt, src, dest, offset);
                         if (s == false)
                         if (s == false)
                         {
                         {
-                            apply_atlas(ad, _linearFilter);
+                            apply_atlas(ad, _linearFilter, _clamp2edge);
                             next_atlas(w, h, tf, ad, walker.getCurrentFolder().c_str());
                             next_atlas(w, h, tf, ad, walker.getCurrentFolder().c_str());
                             s = ad.atlas.add(&ad.mt, src, dest, offset);
                             s = ad.atlas.add(&ad.mt, src, dest, offset);
                             OX_ASSERT(s);
                             OX_ASSERT(s);
                         }
                         }
 
 
+                        //extend = false;
                         if (extend)
                         if (extend)
                         {
                         {
                             //duplicate image edges
                             //duplicate image edges
                             MemoryTexture& mt = ad.mt;
                             MemoryTexture& mt = ad.mt;
                             ImageData tmp;
                             ImageData tmp;
 
 
-                            tmp = mt.lock(Rect(dest.pos.x, dest.pos.y - 1, src.w, 1));
-                            operations::copy(src.getRect(Rect(0, 0, src.w, 1)), tmp);
-
-                            tmp = mt.lock(Rect(dest.pos.x, dest.pos.y + src.h, src.w, 1));
-                            operations::copy(src.getRect(Rect(0, src.h - 1, src.w, 1)), tmp);
-
-                            tmp = mt.lock(Rect(dest.pos.x - 1, dest.pos.y, 1, src.h));
-                            operations::copy(src.getRect(Rect(0, 0, 1, src.h)), tmp);
-
-                            tmp = mt.lock(Rect(dest.pos.x + src.w, dest.pos.y, 1, src.h));
-                            operations::copy(src.getRect(Rect(src.w - 1, 0, 1, src.h)), tmp);
+                            if (bounds.getY() == 0)
+                            {
+                                tmp = mt.lock(Rect(dest.pos.x, dest.pos.y - 1, src.w, 1));
+                                operations::copy(src.getRect(Rect(0, 0, src.w, 1)), tmp);
+                            }
+
+                            if (bounds.getHeight() == im.h)
+                            {
+                                tmp = mt.lock(Rect(dest.pos.x, dest.pos.y + src.h, src.w, 1));
+                                operations::copy(src.getRect(Rect(0, src.h - 1, src.w, 1)), tmp);
+                            }
+
+                            if (bounds.getX() == 0)
+                            {
+                                tmp = mt.lock(Rect(dest.pos.x - 1, dest.pos.y, 1, src.h));
+                                operations::copy(src.getRect(Rect(0, 0, 1, src.h)), tmp);
+                            }
+
+                            if (bounds.getWidth() == im.w)
+                            {
+                                tmp = mt.lock(Rect(dest.pos.x + src.w, dest.pos.y, 1, src.h));
+                                operations::copy(src.getRect(Rect(src.w - 1, 0, 1, src.h)), tmp);
+                            }
                         }
                         }
 
 
 
 
@@ -575,12 +599,12 @@ namespace oxygine
 
 
                 ra->init(frames, columns, walker.getScaleFactor(), 1.0f / walker.getScaleFactor());
                 ra->init(frames, columns, walker.getScaleFactor(), 1.0f / walker.getScaleFactor());
                 ra->setParent(this);
                 ra->setParent(this);
-                context.resources->add(ra);
+                context.resources->add(ra, context.options->shortenIDS);
             }
             }
 
 
         }
         }
 
 
-        apply_atlas(ad, _linearFilter);
+        apply_atlas(ad, _linearFilter, _clamp2edge);
 
 
         for (std::vector<ResAnim*>::iterator i = anims.begin(); i != anims.end(); ++i)
         for (std::vector<ResAnim*>::iterator i = anims.begin(); i != anims.end(); ++i)
         {
         {
@@ -801,7 +825,7 @@ namespace oxygine
 
 
                 ra->init(frames, columns, walker.getScaleFactor(), 1.0f / frame_scale);
                 ra->init(frames, columns, walker.getScaleFactor(), 1.0f / frame_scale);
                 ra->setParent(this);
                 ra->setParent(this);
-                context.resources->add(ra);
+                context.resources->add(ra, context.options->shortenIDS);
             }
             }
         }
         }
     }
     }

+ 3 - 2
oxygine/src/res/ResFontBM.h

@@ -12,6 +12,7 @@ namespace oxygine
 
 
     DECLARE_SMART(NativeTexture, spNativeTexture);
     DECLARE_SMART(NativeTexture, spNativeTexture);
 
 
+
     class ResFontBM: public ResFont
     class ResFontBM: public ResFont
     {
     {
     public:
     public:
@@ -22,8 +23,8 @@ namespace oxygine
         ResFontBM();
         ResFontBM();
         ~ResFontBM();
         ~ResFontBM();
 
 
-        /**use it only if you want create font without Resources*/
-        void init(const char* fntPath, bool premultipliedAlpha = true);
+        /**loads "fnt" font from file, supported XML and text format*/
+        void init(const char* fntPath, bool premultipliedAlpha = false);
 
 
         void cleanup();
         void cleanup();
 
 

+ 3 - 3
oxygine/src/res/ResStarlingAtlas.cpp

@@ -156,11 +156,11 @@ namespace oxygine
 
 
     }
     }
 
 
-    void load_texture(const std::string& file, spNativeTexture nt, bool linearFilter, LoadResourcesContext* load_context);
+    void load_texture(const std::string& file, spNativeTexture nt, bool linearFilter, bool clamp2edge, LoadResourcesContext* load_context);
 
 
     void ResStarlingAtlas::_restore(Restorable* r, void*)
     void ResStarlingAtlas::_restore(Restorable* r, void*)
     {
     {
-        load_texture(_imagePath, _texture, true, &RestoreResourcesContext::instance);
+        load_texture(_imagePath, _texture, true, true, &RestoreResourcesContext::instance);
         _texture->reg(CLOSURE(this, &ResStarlingAtlas::_restore), 0);
         _texture->reg(CLOSURE(this, &ResStarlingAtlas::_restore), 0);
     }
     }
 
 
@@ -169,7 +169,7 @@ namespace oxygine
         if (!load_context->isNeedProceed(_texture))
         if (!load_context->isNeedProceed(_texture))
             return;
             return;
 
 
-        load_texture(_imagePath, _texture, true, load_context);
+        load_texture(_imagePath, _texture, true, true, load_context);
         _texture->reg(CLOSURE(this, &ResStarlingAtlas::_restore), 0);
         _texture->reg(CLOSURE(this, &ResStarlingAtlas::_restore), 0);
     }
     }
 
 

+ 70 - 63
oxygine/src/res/Resources.cpp

@@ -117,21 +117,11 @@ namespace oxygine
 
 
     void Resources::free()
     void Resources::free()
     {
     {
-        /*
-        for (resources::iterator i = _owned.begin(); i != _owned.end(); ++i)
-        {
-            Resource *res = (*i);
-            delete res;
-        }
-        _owned.clear();
-        */
-        _fastAccessResources.clear();
+        _resourcesMap.clear();
         _resources.clear();
         _resources.clear();
 
 
         for (size_t i = 0; i < _docs.size(); ++i)
         for (size_t i = 0; i < _docs.size(); ++i)
-        {
             delete _docs[i];
             delete _docs[i];
-        }
         _docs.clear();
         _docs.clear();
 
 
         __freeName();
         __freeName();
@@ -176,33 +166,26 @@ namespace oxygine
         }
         }
     };
     };
 
 
-
-    void Resources::loadXML(
-        const std::string& xml_name,
-        LoadResourcesContext* load_context,
-        bool load_completely, bool use_load_counter,
-        const std::string& prebuilt_folder_)
+    void Resources::load(const std::string& xmlFile, const ResourcesLoadOptions& opt)
     {
     {
-
-
-        _name = xml_name;
-        _loadCounter = load_completely ? 1 : 0;
+        _name = xmlFile;
+        _loadCounter = opt.loadCompletely ? 1 : 0;
 
 
 
 
         FS_LOG("step0");
         FS_LOG("step0");
         file::buffer fb;
         file::buffer fb;
-        file::read(xml_name.c_str(), fb);
+        file::read(xmlFile.c_str(), fb);
 
 
         FS_LOG("step1");
         FS_LOG("step1");
 
 
 
 
-        updateName(xml_name);
+        updateName(xmlFile);
 
 
         char destHead[255];
         char destHead[255];
         char destTail[255];
         char destTail[255];
-        path::split(xml_name.c_str(), destHead, destTail);
+        path::split(xmlFile.c_str(), destHead, destTail);
 
 
-        std::string prebuilt_folder = prebuilt_folder_ + "/" + destTail + ".ox/";
+        std::string prebuilt_folder = opt.prebuilFolder + "/" + destTail + ".ox/";
         if (prebuilt_folder[0] == '/')
         if (prebuilt_folder[0] == '/')
         {
         {
             prebuilt_folder.erase(prebuilt_folder.begin());
             prebuilt_folder.erase(prebuilt_folder.begin());
@@ -225,7 +208,7 @@ namespace oxygine
 
 
         if (!fb.data.size())
         if (!fb.data.size())
         {
         {
-            OX_ASSERT(fb.data.size()  && "can't find xml file");
+            OX_ASSERT(fb.data.size() && "can't find xml file");
             return;
             return;
         }
         }
 
 
@@ -240,22 +223,21 @@ namespace oxygine
         if (!resources_meta.empty())
         if (!resources_meta.empty())
         {
         {
             int metaVersion = resources_meta.attribute("version").as_int(0);
             int metaVersion = resources_meta.attribute("version").as_int(0);
-            OX_ASSERT(metaVersion <= 2  && "Please rebuild xmls with latest 'oxyresbuild' tool");
+            OX_ASSERT(metaVersion <= 2 && "Please rebuild xmls with latest 'oxyresbuild' tool");
         }
         }
 
 
 
 
         std::string id;
         std::string id;
-        //string file;
-        std::string rect_str;
 
 
         FS_LOG("loading xml resources");
         FS_LOG("loading xml resources");
 
 
         std::string xmlFolder = destHead;
         std::string xmlFolder = destHead;
-        XmlWalker walker(&xmlFolder, "", 1.0f, load_completely, true, resources, resources_meta);
+        XmlWalker walker(&xmlFolder, "", 1.0f, opt.loadCompletely, true, resources, resources_meta);
 
 
         while (true)
         while (true)
         {
         {
             CreateResourceContext context;
             CreateResourceContext context;
+            context.options = &opt;
             context.walker = walker.next();
             context.walker = walker.next();
             if (context.walker.empty())
             if (context.walker.empty())
                 break;
                 break;
@@ -274,7 +256,7 @@ namespace oxygine
             registeredResource& r = *i;
             registeredResource& r = *i;
 
 
 
 
-            context.xml_name = &xml_name;
+            context.xml_name = &xmlFile;
             context.resources = this;
             context.resources = this;
 
 
             std::string prebuilt_xml_folder = prebuilt_folder + type + "/";
             std::string prebuilt_xml_folder = prebuilt_folder + type + "/";
@@ -284,59 +266,86 @@ namespace oxygine
             FS_LOG("resource: %s ", name);
             FS_LOG("resource: %s ", name);
             Resource* res = r.cb(context);
             Resource* res = r.cb(context);
             OX_ASSERT(res);
             OX_ASSERT(res);
-            res->setUseLoadCounter(use_load_counter);
+            res->setUseLoadCounter(opt.useLoadCounter);
 
 
             if (res)
             if (res)
             {
             {
-                bool load = context.walker.getLoad();
-
-                //res-> = child;
-                if (load)
-                    res->load(load_context);
+                if (context.walker.getLoad())
+                    res->load(opt.loadContext);
                 res->setParent(this);
                 res->setParent(this);
                 _resources.push_back(res);
                 _resources.push_back(res);
-                //_owned.push_back(res);
             }
             }
         }
         }
 
 
-        sort();
         FS_LOG("xml loaded");
         FS_LOG("xml loaded");
     }
     }
 
 
-    void Resources::add(Resource* r)
+    void Resources::loadXML(
+        const std::string& xml_name,
+        LoadResourcesContext* load_context,
+        bool load_completely, bool use_load_counter,
+        const std::string& prebuilt_folder_)
+    {
+        ResourcesLoadOptions opt;
+        opt.loadContext = load_context;
+        opt.loadCompletely = load_completely;
+        opt.useLoadCounter = use_load_counter;
+        opt.prebuilFolder = prebuilt_folder_;
+        load(xml_name, opt);
+    }
+
+    void Resources::addShortIDS()
+    {
+
+    }
+
+    void Resources::collect(resources&)
+    {
+
+    }
+
+    void Resources::add(Resource* r, bool accessByShortenID)
     {
     {
         OX_ASSERT(r);
         OX_ASSERT(r);
         if (!r)
         if (!r)
             return;
             return;
-        /*
-        OX_ASSERT(_resources[r->getName()] == 0);
 
 
-        _resources[r->getName()] = r;
-        */
+        std::string name = lower(r->getName());
+        r->setName(name);
+        _resourcesMap[name] = r;
 
 
-        //todo insert to correct place
-        r->setName(lower(r->getName()));
-        _fastAccessResources.push_back(r);
-
-        //if (own)
-        //  _owned.push_back(r);
-        //OX_ASSERT(0);
+        if (accessByShortenID)
+        {
+            std::string shortName = path::extractFileName(name);
+            _resourcesMap[shortName] = r;
+        }
     }
     }
 
 
 
 
-    void Resources::print()
+    void Resources::print() const
     {
     {
         log::message("resources:\n");
         log::message("resources:\n");
-        for (resources::iterator i = _fastAccessResources.begin(); i != _fastAccessResources.end(); ++i)
+#ifdef __S3E__
+        for (resourcesMap::const_iterator i = _resourcesMap.begin(); i != _resourcesMap.end(); ++i)
+#else
+        for (resourcesMap::const_iterator i = _resourcesMap.cbegin(); i != _resourcesMap.cend(); ++i)
+#endif
+
         {
         {
-            spResource res = *i;
+            spResource res = i->second;
             log::message("%s\n", res->getName().c_str());
             log::message("%s\n", res->getName().c_str());
         }
         }
-    }
 
 
-    void Resources::sort()
-    {
-        std::sort(_fastAccessResources.begin(), _fastAccessResources.end(), ObjectBasePredicate());
+        /*
+        unsigned n = _resourcesMap.bucket_count();
+
+        for (unsigned i=0; i<n; ++i) {
+            log::message("bucket %d: ", i);
+            for (auto it = _resourcesMap.begin(i); it!=_resourcesMap.end(i); ++it)
+                log::message("%s, ", it->first.c_str());
+            log::messageln(" ");
+        }
+        */
     }
     }
 
 
     Resources::resources& Resources::_getResources()
     Resources::resources& Resources::_getResources()
@@ -348,13 +357,11 @@ namespace oxygine
     {
     {
         std::string id = lower(id_);
         std::string id = lower(id_);
 
 
-        resources::const_iterator it = std::lower_bound(_fastAccessResources.begin(), _fastAccessResources.end(),
-                                       id.c_str(), ObjectBasePredicate());
+        resourcesMap::const_iterator it = _resourcesMap.find(id);
 
 
-        if (it != _fastAccessResources.end())
+        if (it != _resourcesMap.end())
         {
         {
-            if ((*it)->getName() == id)
-                return (*it).get();
+            return it->second.get();
         }
         }
 
 
         handleErrorPolicy(ep, "can't find resource: '%s' in '%s'", id.c_str(), _name.c_str());
         handleErrorPolicy(ep, "can't find resource: '%s' in '%s'", id.c_str(), _name.c_str());

+ 44 - 16
oxygine/src/res/Resources.h

@@ -7,6 +7,11 @@
 #include "closure/closure.h"
 #include "closure/closure.h"
 #include "core/Object.h"
 #include "core/Object.h"
 #include "Resource.h"
 #include "Resource.h"
+#ifdef __S3E__
+#include <map>
+#else
+#include <unordered_map>
+#endif
 
 
 namespace pugi
 namespace pugi
 {
 {
@@ -22,6 +27,17 @@ namespace oxygine
     class CreateResourceContext;
     class CreateResourceContext;
     class LoadResourcesContext;
     class LoadResourcesContext;
 
 
+    class ResourcesLoadOptions
+    {
+    public:
+        ResourcesLoadOptions() : loadCompletely(true), useLoadCounter(false), loadContext(0), shortenIDS(false) {};
+
+        bool loadCompletely;
+        bool useLoadCounter;
+        bool shortenIDS;
+        std::string prebuilFolder;
+        LoadResourcesContext* loadContext;
+    };
 
 
     class Resources: public _Resource
     class Resources: public _Resource
     {
     {
@@ -37,13 +53,14 @@ namespace oxygine
         static void registerResourceType(createResourceCallback creationCallback, const char* resTypeID);
         static void registerResourceType(createResourceCallback creationCallback, const char* resTypeID);
         static void unregisterResourceType(const char* resTypeID);
         static void unregisterResourceType(const char* resTypeID);
 
 
-
         Resources();
         Resources();
         ~Resources();
         ~Resources();
 
 
-        /**Loads resources from xml file.
+        /**
+        DEPRECATED, USE load method
+        Loads resources from xml file.
         @param xml file path
         @param xml file path
-        @param used for multithreading loading
+        @param used for multi threading loading
         @param should be each resource loaded completely includes internal heavy data (atlasses/textures/buffers) or load only their definition. Could be overloaded in xml: <your_res_type ... load = "false"/>
         @param should be each resource loaded completely includes internal heavy data (atlasses/textures/buffers) or load only their definition. Could be overloaded in xml: <your_res_type ... load = "false"/>
         @param use load counter internally
         @param use load counter internally
         @param use not standard folder with prebuilt resources (atlasses, fonts, etc)
         @param use not standard folder with prebuilt resources (atlasses, fonts, etc)
@@ -52,50 +69,56 @@ namespace oxygine
                      bool load_completely = true, bool use_load_counter = false,
                      bool load_completely = true, bool use_load_counter = false,
                      const std::string& prebuilt_folder = "");
                      const std::string& prebuilt_folder = "");
 
 
-        /**Adds your own Resource and becomes resource owner if Own is true. Owned resource will be deleted from destructor by calling 'delete'.*/
-        void add(Resource* r);
 
 
-        /**Calls Resource::load for each resoure in the list*/
+        /**Loads resources from xml file. Load could be called multiple times for different xml files.
+        @param xml file paths
+        @param options
+        */
+        void load(const std::string& xmlFile, const ResourcesLoadOptions& opt = ResourcesLoadOptions());
+
+        /**Adds Resource*/
+        void add(Resource* r, bool accessByShortenID = false);
+
+        /**Calls Resource::load for each resource in the list*/
         void load(LoadResourcesContext* context = 0, ResLoadedCallback cb = ResLoadedCallback());
         void load(LoadResourcesContext* context = 0, ResLoadedCallback cb = ResLoadedCallback());
 
 
         /**Unloads data from memory, all resources handles remain valid*/
         /**Unloads data from memory, all resources handles remain valid*/
         void unload();
         void unload();
 
 
-        /**Completely deletes all resources*/
+        /**Completely deletes all loaded resources*/
         void free();
         void free();
 
 
         /** get resource by id, no case sensitive
         /** get resource by id, no case sensitive
         @param resource id
         @param resource id
-        @param if showError is true and resource is missing warning/assert will appear
         */
         */
         Resource* get(const std::string& id, error_policy ep = ep_show_error) const;
         Resource* get(const std::string& id, error_policy ep = ep_show_error) const;
 
 
         /** returns resource by index */
         /** returns resource by index */
-        Resource* get(int index) const {return _fastAccessResources[index].get();}
-        int       getCount() const {return (int)_fastAccessResources.size();}
+        //Resource* get(int index) const {return _fastAccessResources.at(index).get();}
+        //int       getCount() const {return (int)_fastAccessResources.size();}
 
 
         Resource* operator[](const std::string& id) { return get(id); }
         Resource* operator[](const std::string& id) { return get(id); }
 
 
         /** get resource by id
         /** get resource by id
         @param resource id
         @param resource id
-        @param if safe is true and resource is missing warning/assert will appear
         */
         */
         ResAnim* getResAnim(const std::string& id, error_policy ep = ep_show_error) const;
         ResAnim* getResAnim(const std::string& id, error_policy ep = ep_show_error) const;
 
 
         /** get animation resource by id
         /** get animation resource by id
         @param resource id
         @param resource id
-        @param if safe is true and resource is missing warning/assert will appear
         */
         */
         ResFont* getResFont(const std::string& id, error_policy ep = ep_show_error) const;
         ResFont* getResFont(const std::string& id, error_policy ep = ep_show_error) const;
 
 
         template<class T>
         template<class T>
         T* getT(const std::string& id, error_policy ep = ep_show_error) const { return safeCast<T*>(get(id, ep)); }
         T* getT(const std::string& id, error_policy ep = ep_show_error) const { return safeCast<T*>(get(id, ep)); }
 
 
-        /**sorting manually added resources*/
-        void sort();
         /**debug function. prints all loaded resources*/
         /**debug function. prints all loaded resources*/
-        void print();
+        void print() const;
+
+        /**collects all resources into vector*/
+        void collect(resources&);
 
 
+        void addShortIDS();
 
 
         resources& _getResources();
         resources& _getResources();
 
 
@@ -129,7 +152,12 @@ namespace oxygine
 
 
 
 
         resources _resources;
         resources _resources;
-        resources _fastAccessResources;
+#ifdef __S3E__
+        typedef std::map<std::string, spResource> resourcesMap;
+#else
+        typedef std::unordered_map<std::string, spResource> resourcesMap;
+#endif
+        resourcesMap _resourcesMap;
 
 
 
 
         typedef std::vector< registeredResource > registeredResources;
         typedef std::vector< registeredResource > registeredResources;

+ 4 - 4
oxygine/src/text_utils/Node.cpp

@@ -72,13 +72,13 @@ namespace oxygine
             }
             }
         }
         }
 
 
-        const Symbol* Node::getSymbol(int& pos) const
+        Symbol* Node::getSymbol(int& pos)
         {
         {
             Node* node = _firstChild;
             Node* node = _firstChild;
             while (node)
             while (node)
             {
             {
                 int num = 0;
                 int num = 0;
-                const Symbol* res = node->getSymbol(pos);
+                Symbol* res = node->getSymbol(pos);
                 if (res)
                 if (res)
                     return res;
                     return res;
                 node = node->_nextSibling;
                 node = node->_nextSibling;
@@ -134,9 +134,9 @@ namespace oxygine
             }
             }
         }
         }
 
 
-        const Symbol* TextNode::getSymbol(int& pos) const
+        Symbol* TextNode::getSymbol(int& pos)
         {
         {
-            if ((int)_data.size() < pos)
+            if ((int)_data.size() > pos)
                 return &_data[pos];
                 return &_data[pos];
             pos -= _data.size();
             pos -= _data.size();
             return Node::getSymbol(pos);
             return Node::getSymbol(pos);

+ 2 - 2
oxygine/src/text_utils/Node.h

@@ -48,7 +48,7 @@ namespace oxygine
             void resize(Aligner& rd);
             void resize(Aligner& rd);
             void finalPass(Aligner& rd);
             void finalPass(Aligner& rd);
             void drawChildren(DrawContext& dc);
             void drawChildren(DrawContext& dc);
-            virtual const Symbol* getSymbol(int& pos) const;
+            virtual Symbol* getSymbol(int& pos);
 
 
             virtual void draw(DrawContext& dc);
             virtual void draw(DrawContext& dc);
 
 
@@ -73,7 +73,7 @@ namespace oxygine
             void _finalPass(Aligner& rd);
             void _finalPass(Aligner& rd);
             void draw(DrawContext& dc);
             void draw(DrawContext& dc);
 
 
-            const Symbol* getSymbol(int& pos) const OVERRIDE;
+            Symbol* getSymbol(int& pos) OVERRIDE;
 
 
 #ifdef OX_DEBUG
 #ifdef OX_DEBUG
             std::string _text;//only for debug
             std::string _text;//only for debug

+ 9 - 3
oxygine/src/utils/ImageUtils.cpp

@@ -1,7 +1,7 @@
 #include "ImageUtils.h"
 #include "ImageUtils.h"
 #include "core/ImageData.h"
 #include "core/ImageData.h"
-
-#include "png.h"
+#include "MemoryTexture.h"
+//#include "png.h"
 extern "C"
 extern "C"
 {
 {
 #ifdef OX_HAVE_LIBJPEG
 #ifdef OX_HAVE_LIBJPEG
@@ -16,8 +16,14 @@ extern "C"
 
 
 namespace oxygine
 namespace oxygine
 {
 {
-    void saveImage(const ImageData& im, const char* path, const char* format)
+    void saveImage(const ImageData& im_, const char* path, const char* format)
     {
     {
+        MemoryTexture src;
+        src.init(im_);
+        MemoryTexture dest;
+        src.convert(dest, TF_B8G8R8A8);
+        const ImageData& im = dest.lock();
+
         file::handle h = file::open(path, "wb");
         file::handle h = file::open(path, "wb");
         file::autoClose ac(h);
         file::autoClose ac(h);
         char header[18] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
         char header[18] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

+ 26 - 0
oxygine/src/utils/stringUtils.cpp

@@ -189,6 +189,32 @@ namespace oxygine
             }
             }
             *dest = 0;
             *dest = 0;
         }
         }
+
+        std::string extractFileName(const std::string& path)
+        {
+            size_t pos = path.find_last_of("\\/") + 1;
+            std::string name = path.substr(pos, path.size() - pos);
+            return name;
+        }
+
+        std::string extractBaseFileName(const std::string& filename)
+        {
+            size_t pos = filename.find_first_of('.');
+            if (pos == std::string::npos)
+                pos = filename.size();
+            std::string name = filename.substr(0, pos);
+            return name;
+        }
+
+        std::string extractFileExt(const std::string& filename)
+        {
+            size_t pos = filename.find_first_of(".");
+            if (pos == std::string::npos)
+                return "";
+            pos += 1;
+            std::string name = filename.substr(pos, filename.size() - pos);
+            return name;
+        }
     }
     }
 
 
     const char* getNextCode(int& code, const char* utf8str)
     const char* getNextCode(int& code, const char* utf8str)

+ 12 - 0
oxygine/src/utils/stringUtils.h

@@ -19,6 +19,18 @@ namespace oxygine
         void splitExt(const char* src, char* destHead, char* destTail);
         void splitExt(const char* src, char* destHead, char* destTail);
 
 
         void normalize(const char* src, char* dest);
         void normalize(const char* src, char* dest);
+
+        /**some/file/path.png   ->  path.png*/
+        std::string extractFileName(const std::string& path);
+
+        /**
+        name.png             ->  name
+        some/file/path.png   ->  some/file/path
+        */
+        std::string extractBaseFileName(const std::string& filename);
+
+        /**some/file/path.png   ->  png*/
+        std::string extractFileExt(const std::string& filename);
     }
     }
 
 
     std::string lower(const std::string& str);
     std::string lower(const std::string& str);

+ 1 - 1
readme/Android.txt

@@ -3,7 +3,7 @@
 =================================================================================================
 =================================================================================================
 How to build. Steps:
 How to build. Steps:
 - Install Android NDK (https://developer.android.com/tools/sdk/ndk/index.html) and set it up
 - Install Android NDK (https://developer.android.com/tools/sdk/ndk/index.html) and set it up
-- Install Android SDK (https://developer.android.com/sdk/index.html) - version 16
+- Install Android SDK Tools (https://developer.android.com/intl/ru/sdk/index.html#Other), launch SDK Manager and install Android SDK v16
 - Install apache-ant (http://ant.apache.org/bindownload.cgi)
 - Install apache-ant (http://ant.apache.org/bindownload.cgi)
 - Install JDK version 6/7
 - Install JDK version 6/7
 - Configure environment variables properly:
 - Configure environment variables properly: