Răsfoiți Sursa

migrate from bitbucket

dmuratshin 10 ani în urmă
părinte
comite
014d653d68
80 a modificat fișierele cu 4610 adăugiri și 28 ștergeri
  1. 11 28
      .gitignore
  2. 17 0
      Android.mk
  3. 20 0
      CMakeLists.txt
  4. 18 0
      android/billing/AndroidManifest.xml
  5. 17 0
      android/billing/ant.properties
  6. 30 0
      android/billing/billing.iml
  7. 92 0
      android/billing/build.xml
  8. BIN
      android/billing/libs/android-support-v4.jar
  9. BIN
      android/billing/libs/in-app-purchasing-2.0.61.jar
  10. 20 0
      android/billing/proguard-project.txt
  11. 16 0
      android/billing/project.properties
  12. 144 0
      android/billing/src/com/android/vending/billing/IInAppBillingService.aidl
  13. 34 0
      android/billing/src/org/oxygine/billing/Billing.java
  14. 282 0
      android/billing/src/org/oxygine/billing/BillingAmazon.java
  15. 271 0
      android/billing/src/org/oxygine/billing/BillingGoogle.java
  16. 55 0
      example/HelloWorldBilling/data/demo/big.bmfc
  17. BIN
      example/HelloWorldBilling/data/demo/button.png
  18. BIN
      example/HelloWorldBilling/data/demo/eng.txt
  19. 109 0
      example/HelloWorldBilling/data/demo/font.fnt
  20. BIN
      example/HelloWorldBilling/data/demo/font.png
  21. 6 0
      example/HelloWorldBilling/data/demo/fonts.xml
  22. BIN
      example/HelloWorldBilling/data/demo/loading.png
  23. BIN
      example/HelloWorldBilling/data/demo/logo2.png
  24. 55 0
      example/HelloWorldBilling/data/demo/main.bmfc
  25. 9 0
      example/HelloWorldBilling/data/demo/res_ui.xml
  26. 109 0
      example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/big.fnt
  27. BIN
      example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/big_0.png
  28. 109 0
      example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/main.fnt
  29. BIN
      example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/main_0.png
  30. 1 0
      example/HelloWorldBilling/data/ext/fonts.xml.ox/meta.xml
  31. 48 0
      example/HelloWorldBilling/proj.android/AndroidManifest.xml
  32. 18 0
      example/HelloWorldBilling/proj.android/ant.properties
  33. 1 0
      example/HelloWorldBilling/proj.android/ant_debug.bat
  34. 2 0
      example/HelloWorldBilling/proj.android/ant_debug.sh
  35. 3 0
      example/HelloWorldBilling/proj.android/build-run.bat
  36. 4 0
      example/HelloWorldBilling/proj.android/build-run.sh
  37. 1 0
      example/HelloWorldBilling/proj.android/build.bat
  38. 2 0
      example/HelloWorldBilling/proj.android/build.sh
  39. 93 0
      example/HelloWorldBilling/proj.android/build.xml
  40. 11 0
      example/HelloWorldBilling/proj.android/default.properties
  41. 2 0
      example/HelloWorldBilling/proj.android/install.bat
  42. 3 0
      example/HelloWorldBilling/proj.android/install.sh
  43. 1 0
      example/HelloWorldBilling/proj.android/jni/Android.mk
  44. 5 0
      example/HelloWorldBilling/proj.android/jni/Application.mk
  45. 24 0
      example/HelloWorldBilling/proj.android/jni/src/Android.mk
  46. 16 0
      example/HelloWorldBilling/proj.android/project.properties
  47. BIN
      example/HelloWorldBilling/proj.android/res/drawable-hdpi/ic_launcher.png
  48. BIN
      example/HelloWorldBilling/proj.android/res/drawable-mdpi/ic_launcher.png
  49. BIN
      example/HelloWorldBilling/proj.android/res/drawable-xhdpi/ic_launcher.png
  50. BIN
      example/HelloWorldBilling/proj.android/res/drawable-xxhdpi/ic_launcher.png
  51. 13 0
      example/HelloWorldBilling/proj.android/res/layout/main.xml
  52. 4 0
      example/HelloWorldBilling/proj.android/res/values/strings.xml
  53. 29 0
      example/HelloWorldBilling/proj.android/src/org/oxygine/HelloWorldBilling/MainActivity.java
  54. 19 0
      example/HelloWorldBilling/proj.cmake/CMakeLists.txt
  55. 16 0
      example/HelloWorldBilling/proj.cmake/run.sh
  56. 25 0
      example/HelloWorldBilling/proj.emscripten/CMakeLists.txt
  57. 7 0
      example/HelloWorldBilling/proj.emscripten/build.bat
  58. 7 0
      example/HelloWorldBilling/proj.emscripten/build_release.bat
  59. 51 0
      example/HelloWorldBilling/proj.ios/HelloWorldBilling/HelloWorldBilling_ios-Info.plist
  60. 53 0
      example/HelloWorldBilling/proj.ios/HelloWorldBilling/Images.xcassets/AppIcon.appiconset/Contents.json
  61. 49 0
      example/HelloWorldBilling/proj.ios/HelloWorldBilling/Images.xcassets/LaunchImage.launchimage/Contents.json
  62. 51 0
      example/HelloWorldBilling/proj.ios/HelloWorldBilling/LaunchImage.launchimage/Contents.json
  63. 465 0
      example/HelloWorldBilling/proj.ios/HelloWorldBilling_ios.xcodeproj/project.pbxproj
  64. 58 0
      example/HelloWorldBilling/proj.macosx/HelloWorldBilling/Images.xcassets/AppIcon.appiconset/Contents.json
  65. 34 0
      example/HelloWorldBilling/proj.macosx/HelloWorldBilling_macosx-Info.plist
  66. 491 0
      example/HelloWorldBilling/proj.macosx/HelloWorldBilling_macosx.xcodeproj/project.pbxproj
  67. 48 0
      example/HelloWorldBilling/proj.win32/HelloWorldBilling.sln
  68. 128 0
      example/HelloWorldBilling/proj.win32/HelloWorldBilling.vcxproj
  69. 54 0
      example/HelloWorldBilling/proj.win32/HelloWorldBilling.vcxproj.filters
  70. 151 0
      example/HelloWorldBilling/src/entry_point.cpp
  71. 57 0
      example/HelloWorldBilling/src/example.cpp
  72. 4 0
      example/HelloWorldBilling/src/example.h
  73. 240 0
      example/HelloWorldBilling/src/test.cpp
  74. 77 0
      example/HelloWorldBilling/src/test.h
  75. 256 0
      src/android/AndroidBilling.cpp
  76. 12 0
      src/android/AndroidBilling.h
  77. 155 0
      src/billing.cpp
  78. 119 0
      src/billing.h
  79. 266 0
      src/sim/BillingSimulator.cpp
  80. 12 0
      src/sim/BillingSimulator.h

+ 11 - 28
.gitignore

@@ -1,28 +1,11 @@
-# Compiled Object files
-*.slo
-*.lo
-*.o
-*.obj
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Compiled Dynamic libraries
-*.so
-*.dylib
-*.dll
-
-# Fortran module files
-*.mod
-
-# Compiled Static libraries
-*.lai
-*.la
-*.a
-*.lib
-
-# Executables
-*.exe
-*.out
-*.app
+android/billing/gen/
+android/billing/bin/
+example/HelloWorldBilling/proj.win32/Debug/
+*.sdf
+example/HelloWorldBilling/proj.android/bin/
+example/HelloWorldBilling/proj.android/gen/
+example/HelloWorldBilling/proj.android/obj/local/armeabi-v7a/objs/
+example/HelloWorldBilling/proj.android/obj/
+*.opensdf
+example/HelloWorldBilling/proj.android/out/
+example/HelloWorldBilling/proj.android/.idea/

+ 17 - 0
Android.mk

@@ -0,0 +1,17 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := oxygine-billing_static
+LOCAL_MODULE_FILENAME := liboxygine-billing
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../oxygine-framework/oxygine/src/ \
+					$(LOCAL_PATH)/src/ \
+
+
+LOCAL_SRC_FILES :=  src/billing.cpp \
+					src/android/AndroidBilling.cpp \
+
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src/
+
+include $(BUILD_STATIC_LIBRARY)

+ 20 - 0
CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required (VERSION 2.6)
+project (OXYGINE_BILLING)
+
+set(OXYGINE_BILLING_INCLUDE_DIRS 
+	${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+include_directories(${OXYGINE_BILLING_INCLUDE_DIRS})
+add_library(oxygine-billing STATIC 
+	src/billing.cpp 
+	src/billing.h
+	src/sim/BillingSimulator.cpp 
+	src/sim/BillingSimulator.h
+)
+
+#target_link_libraries(oxyginemagicparticles)
+
+set(OXYGINE_BILLING_INCLUDE_DIRS ${OXYGINE_BILLING_INCLUDE_DIRS} PARENT_SCOPE)
+set(OXYGINE_BILLING_LIBS ${OXYGINE_BILLING_LIBS} PARENT_SCOPE)

+ 18 - 0
android/billing/AndroidManifest.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="org.oxygine.billing"
+          android:versionCode="1"
+          android:versionName="1.0">
+
+
+	<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19"/>
+	<uses-permission android:name="com.android.vending.BILLING"/>
+
+	<receiver android:name="com.amazon.device.iap.ResponseReceiver" >
+            <intent-filter>
+                <action
+                    android:name="com.amazon.inapp.purchasing.NOTIFY"
+                    android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY" />
+            </intent-filter>
+    </receiver>
+</manifest> 

+ 17 - 0
android/billing/ant.properties

@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+

+ 30 - 0
android/billing/billing.iml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="LIBRARY_PROJECT" value="true" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 10 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="extension" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/libs/in-app-purchasing-2.0.61.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+  </component>
+</module>
+

+ 92 - 0
android/billing/build.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="testttt" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties"/>
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties"/>
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env"/>
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME"/>
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties"/>
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+            />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true"/>
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml"/>
+
+</project>

BIN
android/billing/libs/android-support-v4.jar


BIN
android/billing/libs/in-app-purchasing-2.0.61.jar


+ 20 - 0
android/billing/proguard-project.txt

@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 16 - 0
android/billing/project.properties

@@ -0,0 +1,16 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+android.library=true
+# Project target.
+target=android-10
+android.library.reference.1=../../../oxygine-framework/oxygine/SDL/android/extension

+ 144 - 0
android/billing/src/com/android/vending/billing/IInAppBillingService.aidl

@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.vending.billing;
+
+import android.os.Bundle;
+
+/**
+ * InAppBillingService is the service that provides in-app billing version 3 and beyond.
+ * This service provides the following features:
+ * 1. Provides a new API to get details of in-app items published for the app including
+ *    price, type, title and description.
+ * 2. The purchase flow is synchronous and purchase information is available immediately
+ *    after it completes.
+ * 3. Purchase information of in-app purchases is maintained within the Google Play system
+ *    till the purchase is consumed.
+ * 4. An API to consume a purchase of an inapp item. All purchases of one-time
+ *    in-app items are consumable and thereafter can be purchased again.
+ * 5. An API to get current purchases of the user immediately. This will not contain any
+ *    consumed purchases.
+ *
+ * All calls will give a response code with the following possible values
+ * RESULT_OK = 0 - success
+ * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
+ * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
+ * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
+ * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
+ * RESULT_ERROR = 6 - Fatal error during the API action
+ * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
+ * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
+ */
+interface IInAppBillingService {
+    /**
+     * Checks support for the requested billing API version, package and in-app type.
+     * Minimum API version supported by this interface is 3.
+     * @param apiVersion the billing version which the app is using
+     * @param packageName the package name of the calling app
+     * @param type type of the in-app item being purchased "inapp" for one-time purchases
+     *        and "subs" for subscription.
+     * @return RESULT_OK(0) on success, corresponding result code on failures
+     */
+    int isBillingSupported(int apiVersion, String packageName, String type);
+
+    /**
+     * Provides details of a list of SKUs
+     * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
+     * with a list JSON strings containing the productId, price, title and description.
+     * This API can be called with a maximum of 20 SKUs.
+     * @param apiVersion billing API version that the Third-party is using
+     * @param packageName the package name of the calling app
+     * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
+     * @return Bundle containing the following key-value pairs
+     *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+     *              failure as listed above.
+     *         "DETAILS_LIST" with a StringArrayList containing purchase information
+     *              in JSON format similar to:
+     *              '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
+     *                 "title : "Example Title", "description" : "This is an example description" }'
+     */
+    Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
+
+    /**
+     * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
+     * the type, a unique purchase token and an optional developer payload.
+     * @param apiVersion billing API version that the app is using
+     * @param packageName package name of the calling app
+     * @param sku the SKU of the in-app item as published in the developer console
+     * @param type the type of the in-app item ("inapp" for one-time purchases
+     *        and "subs" for subscription).
+     * @param developerPayload optional argument to be sent back with the purchase information
+     * @return Bundle containing the following key-value pairs
+     *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+     *              failure as listed above.
+     *         "BUY_INTENT" - PendingIntent to start the purchase flow
+     *
+     * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
+     * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
+     * If the purchase is successful, the result data will contain the following key-value pairs
+     *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+     *              failure as listed above.
+     *         "INAPP_PURCHASE_DATA" - String in JSON format similar to
+     *              '{"orderId":"12999763169054705758.1371079406387615",
+     *                "packageName":"com.example.app",
+     *                "productId":"exampleSku",
+     *                "purchaseTime":1345678900000,
+     *                "purchaseToken" : "122333444455555",
+     *                "developerPayload":"example developer payload" }'
+     *         "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
+     *                                  was signed with the private key of the developer
+     *                                  TODO: change this to app-specific keys.
+     */
+    Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
+        String developerPayload);
+
+    /**
+     * Returns the current SKUs owned by the user of the type and package name specified along with
+     * purchase information and a signature of the data to be validated.
+     * This will return all SKUs that have been purchased in V3 and managed items purchased using
+     * V1 and V2 that have not been consumed.
+     * @param apiVersion billing API version that the app is using
+     * @param packageName package name of the calling app
+     * @param type the type of the in-app items being requested
+     *        ("inapp" for one-time purchases and "subs" for subscription).
+     * @param continuationToken to be set as null for the first call, if the number of owned
+     *        skus are too many, a continuationToken is returned in the response bundle.
+     *        This method can be called again with the continuation token to get the next set of
+     *        owned skus.
+     * @return Bundle containing the following key-value pairs
+     *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+     *              failure as listed above.
+     *         "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
+     *         "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
+     *         "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
+     *                                      of the purchase information
+     *         "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
+     *                                      next set of in-app purchases. Only set if the
+     *                                      user has more owned skus than the current list.
+     */
+    Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
+
+    /**
+     * Consume the last purchase of the given SKU. This will result in this item being removed
+     * from all subsequent responses to getPurchases() and allow re-purchase of this item.
+     * @param apiVersion billing API version that the app is using
+     * @param packageName package name of the calling app
+     * @param purchaseToken token in the purchase information JSON that identifies the purchase
+     *        to be consumed
+     * @return 0 if consumption succeeded. Appropriate error values for failures.
+     */
+    int consumePurchase(int apiVersion, String packageName, String purchaseToken);
+}

+ 34 - 0
android/billing/src/org/oxygine/billing/Billing.java

@@ -0,0 +1,34 @@
+package org.oxygine.billing;
+
+import org.oxygine.lib.extension.ActivityObserver;
+
+public abstract class Billing extends ActivityObserver {
+    static final public int BILLING_REQUEST_CODE = 1001;
+
+    public static native void nativeBillingPurchased(int responseCode, String data);
+
+    public static native void nativeBillingDetails(String[] items);
+
+    public static native void nativeBillingPurchases(String[] items, String[] signatures);
+    public static void nativeBillingPurchase(String item, String signature)
+    {
+        String[] pr = new String[1];
+        pr[0] = item;
+
+        String[] sg = new String[1];
+        sg[0] = signature;
+        nativeBillingPurchases(pr, sg);
+    }
+
+
+    public abstract void getPurchases();
+
+    public abstract void requestDetails(String[] ids);
+
+    public abstract void purchase(String sku, String payload);
+
+    public abstract void consume(String token);
+
+    public abstract String getCurrency();
+    public abstract String getName();
+}

+ 282 - 0
android/billing/src/org/oxygine/billing/BillingAmazon.java

@@ -0,0 +1,282 @@
+package org.oxygine.billing;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import com.amazon.device.iap.PurchasingListener;
+import com.amazon.device.iap.PurchasingService;
+import com.amazon.device.iap.model.*;
+import org.json.*;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+
+class MyPurchasingListener implements PurchasingListener
+{
+    private static final String TAG = "MyPurchasingListener";
+
+    private String currentUserId = null;
+    private String currentMarketplace = null;
+
+    
+
+    public void handleReceipt(Receipt receipt)
+    {
+        /*
+        {
+            "sku": "com.abc.qwe",
+            "purchaseDate": "Wed Dec 17 20:07:12 GMT+06:00 2014",
+            "itemType": "CONSUMABLE",
+            "receiptId": "q1YqVrJSSs7P1UsrLSqq1MstKSxNLS5JzE2sys_TS8lMzM3PSzEyyFXSUUoBKjQ0MbSwMDI1MjayMLAEipUCxXKMPXzMIwoKXH0zivzdXfJKiyx1S3PKCvNzi4LTzQor_V28cxMzzM1yvEJtgVpKlKwMagE"
+        }
+        */
+
+        JSONObject data = new JSONObject();
+        try
+        {
+
+            data.put("productId", receipt.getSku());
+            data.put("orderId", receipt.getReceiptId());
+            data.put("purchaseState", receipt.isCanceled() ? 2:0);
+            data.put("sandbox", PurchasingService.IS_SANDBOX_MODE);
+            //customData.put("micros", 100);
+            //customData.put("currencyCode", "USD");
+            data.put("purchaseToken", receipt.getReceiptId());
+
+        } catch (JSONException exc)
+        {
+            return;
+        }
+
+        Billing.nativeBillingPurchase(data.toString(), currentUserId);
+    }
+
+    @Override
+    public void onPurchaseResponse(PurchaseResponse response)
+    {
+        final String requestId = response.getRequestId().toString();
+        final String userId = response.getUserData().getUserId();
+        final PurchaseResponse.RequestStatus status = response.getRequestStatus();
+        Log.d(TAG, "onPurchaseResponse: requestId (" + requestId
+                + ") userId ("
+                + userId
+                + ") purchaseRequestStatus ("
+                + status
+                + ")");
+
+        switch (status) {
+            case SUCCESSFUL:
+                final Receipt receipt = response.getReceipt();
+                //iapManager.setAmazonUserId(response.getUserData().getUserId(), response.getUserData().getMarketplace());
+                Log.d(TAG, "onPurchaseResponse: receipt json:" + receipt.toJSON());
+                handleReceipt(receipt);
+                break;
+            case ALREADY_PURCHASED:
+                Log.d(TAG, "onPurchaseResponse: already purchased, should never get here for a consumable.");
+                // This is not applicable for consumable item. It is only
+                // application for entitlement and subscription.
+                // check related samples for more details.
+                break;
+            case INVALID_SKU:
+                Log.d(TAG, "onPurchaseResponse: invalid SKU!  onProductDataResponse should have disabled buy button already.");
+                final Set<String> unavailableSkus = new HashSet<String>();
+                unavailableSkus.add(response.getReceipt().getSku());
+                //iapManager.disablePurchaseForSkus(unavailableSkus);
+                break;
+            case FAILED:
+            case NOT_SUPPORTED:
+                Log.d(TAG, "onPurchaseResponse: failed so remove purchase request from local storage");
+                //iapManager.purchaseFailed(response.getReceipt().getSku());
+                break;
+        }
+    }
+
+    @Override
+    public void onUserDataResponse(final UserDataResponse response)
+    {
+        final UserDataResponse.RequestStatus status = response.getRequestStatus();
+
+        switch(status) {
+            case SUCCESSFUL:
+                currentUserId = response.getUserData().getUserId();
+                currentMarketplace = response.getUserData().getMarketplace();
+                break;
+
+            case FAILED:
+            case NOT_SUPPORTED:
+                // Fail gracefully.
+                break;
+        }
+    }
+
+
+    @Override
+    public void onProductDataResponse(final ProductDataResponse response)
+    {
+        final ProductDataResponse.RequestStatus status = response.getRequestStatus();
+        Log.d(TAG, "onProductDataResponse: RequestStatus (" + status + ")");
+
+        switch (status) {
+            case SUCCESSFUL:
+                Log.d(TAG, "onProductDataResponse: successful.  The item data map in this response includes the valid SKUs");
+                final Set<String> unavailableSkus = response.getUnavailableSkus();
+                Log.d(TAG, "onProductDataResponse: " + unavailableSkus.size() + " unavailable skus");
+                //iapManager.enablePurchaseForSkus(response.getProductData());
+                //iapManager.disablePurchaseForSkus(response.getUnavailableSkus());
+
+
+                Map<String, Product> items = response.getProductData();
+                ArrayList<String> ar = new ArrayList<String>();
+                for (Product item:items.values())
+                {
+                    JSONObject obj = new JSONObject();
+                    try
+                    {
+                        obj.put("productId", item.getSku());
+                        obj.put("price", item.getPrice());
+
+                    } catch (JSONException exc)
+                    {
+
+                    }
+
+                    ar.add(obj.toString());
+                }
+
+                String[] data = ar.toArray(new String[ar.size()]);
+                Billing.nativeBillingDetails(data);
+
+                break;
+            case FAILED:
+            case NOT_SUPPORTED:
+                Log.d(TAG, "onProductDataResponse: failed, should retry request");
+                //iapManager.disableAllPurchases();
+                break;
+        }
+    }
+
+
+    @Override
+    public void onPurchaseUpdatesResponse(final PurchaseUpdatesResponse response)
+    {
+        Log.d(TAG, "onPurchaseUpdatesResponse: requestId (" + response.getRequestId()
+                + ") purchaseUpdatesResponseStatus ("
+                + response.getRequestStatus()
+                + ") userId ("
+                + response.getUserData().getUserId()
+                + ")");
+        final PurchaseUpdatesResponse.RequestStatus status = response.getRequestStatus();
+        switch (status) {
+            case SUCCESSFUL:
+                //iapManager.setAmazonUserId(response.getUserData().getUserId(), response.getUserData().getMarketplace());
+                for (final Receipt receipt : response.getReceipts()) {
+                    handleReceipt(receipt);
+                }
+                if (response.hasMore()) {
+                    PurchasingService.getPurchaseUpdates(false);
+                }
+                //iapManager.refreshOranges();
+                break;
+            case FAILED:
+            case NOT_SUPPORTED:
+                Log.d(TAG, "onProductDataResponse: failed, should retry request");
+                //iapManager.disableAllPurchases();
+                break;
+        }
+
+    }
+}
+
+public class BillingAmazon extends Billing
+{
+    private static final String TAG = "BillingAmazon";
+
+    MyPurchasingListener _listener;
+
+    public BillingAmazon()
+    {
+
+    }
+
+    @Override
+    public String getCurrency()
+    {
+        return "USD";
+    }
+
+    @Override
+    public String getName()
+    {
+        return "amazon";
+    }
+
+    @Override
+    public void onCreate()
+    {
+        _listener = new MyPurchasingListener();
+        PurchasingService.registerListener(_activity.getApplicationContext(), _listener);
+
+        Log.i(TAG, "onCreate: sandbox mode is:" + PurchasingService.IS_SANDBOX_MODE);
+    }
+
+    @Override
+    public void onResume()
+    {
+        PurchasingService.getUserData();
+        PurchasingService.getPurchaseUpdates(false);
+    }
+
+    @Override
+    public void onDestroy()
+    {
+
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data)
+    {
+
+    }
+
+    @Override
+    public void getPurchases()
+    {
+        PurchasingService.getPurchaseUpdates(true);
+    }
+
+    @Override
+    public void requestDetails(final String[] ids)
+    {
+        new Thread(new Runnable()
+        {
+            public void run()
+            {
+                Set<String> st = new HashSet<String>();
+                for (String s:ids)
+                {
+                    st.add(s);
+                }
+
+                PurchasingService.getProductData(st);
+            }
+        }).start();
+    }
+
+    @Override
+    public void purchase(String sku, String payload)
+    {
+        PurchasingService.purchase(sku);
+    }
+
+    @Override
+    public void consume(String token)
+    {
+        PurchasingService.notifyFulfillment(token, FulfillmentResult.FULFILLED);
+    }
+}

+ 271 - 0
android/billing/src/org/oxygine/billing/BillingGoogle.java

@@ -0,0 +1,271 @@
+package org.oxygine.billing;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.*;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Base64;
+import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+//import com.google.android.gms.analytics.HitBuilders;
+//import com.google.android.gms.analytics.Tracker;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Denis on 27.01.14.
+ */
+public class BillingGoogle extends Billing {
+    private static final String TAG = "SDL";
+    static String ORDER_ID = "";
+    String _publicKey;
+    Map<String, ItemData> prices = new HashMap<String, ItemData>();
+    IInAppBillingService _service;
+    ServiceConnection _serviceConn = new ServiceConnection() {
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            _service = null;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            _service = IInAppBillingService.Stub.asInterface(service);
+        }
+    };
+
+    public BillingGoogle(String publicKey) {
+        _publicKey = publicKey;
+    }
+
+    @Override
+    public String getCurrency() {
+        if (!prices.isEmpty()) {
+            String firstKey = prices.keySet().iterator().next();
+            return prices.get(firstKey).curCode;
+        }
+
+        return "";
+    }
+
+    @Override
+    public String getName()
+    {
+        return "google";
+    }
+
+    @Override
+    public void onCreate() {
+        Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+        serviceIntent.setPackage("com.android.vending");
+        _activity.bindService(serviceIntent, _serviceConn, Context.BIND_AUTO_CREATE);               
+    }
+
+
+    @Override
+    public void onResume() {
+
+    }
+
+    @Override
+    public void onDestroy() {
+        if (_service != null) {
+            _activity.unbindService(_serviceConn);
+        }
+    }
+
+    public boolean verify(String data, String signature) {
+        return true;
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == BILLING_REQUEST_CODE) {
+            if (resultCode != Activity.RESULT_OK)
+                return;
+
+            int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
+            if (responseCode != 0)
+                return;
+
+            String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
+            String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
+            if (verify(purchaseData, dataSignature)) {
+                nativeBillingPurchase(purchaseData, dataSignature);
+            }
+        }
+    }
+
+    protected String processPaymentData(String data, String signature) {
+        try {
+            JSONObject paymentData = new JSONObject("{}");
+
+            JSONObject object = new JSONObject(data);
+            String sku = object.getString("productId");
+            ItemData item = prices.get(sku);
+            if (item != null) {
+                object.put("price", item.price);
+                object.put("currencyCode", item.curCode);
+                object.put("micros", item.micros);
+                paymentData.put("customData", object);
+            }
+
+            paymentData.put("data", data);
+            paymentData.put("signature", signature);
+
+            return paymentData.toString();
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    @Override
+    public void getPurchases() {
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    if (_service == null)
+                        return;
+
+                    Log.d(TAG, "billing.getPurchases");
+                    Bundle purchases = _service.getPurchases(3, _activity.getPackageName(), "inapp", null);
+                    int response = purchases.getInt("RESPONSE_CODE");
+                    if (response == 0) {
+                        ArrayList<String> details = purchases.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+                        ArrayList<String> signatures = purchases.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+
+                        nativeBillingPurchases(
+                                details.toArray(new String[details.size()]),
+                                signatures.toArray(new String[signatures.size()]));
+                    }
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+    }
+
+    @Override
+    public void requestDetails(String[] ids) {
+
+        final ArrayList<String> skuList = new ArrayList<String>();
+        for (String id : ids) {
+            skuList.add(id);
+        }
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    if (_service == null)
+                        return;
+
+                    Log.d(TAG, "billing.requestDetails");
+
+                    ArrayList<String> details = new ArrayList<String>();
+
+                    for (int i = 0; i < skuList.size(); i += 20) {
+                        ArrayList<String> items = new ArrayList<String>();
+                        items.addAll(skuList.subList(i, Math.min(i + 20, skuList.size())));
+
+                        Bundle querySkus = new Bundle();
+                        querySkus.putStringArrayList("ITEM_ID_LIST", items);
+
+                        Bundle skuDetails = _service.getSkuDetails(3, _activity.getPackageName(), "inapp", querySkus);
+                        int response = skuDetails.getInt("RESPONSE_CODE");
+                        if (response == 0) {
+                            ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
+                            details.addAll(responseList);
+
+                            for (String thisResponse : responseList) {
+                                try {
+                                    JSONObject object = new JSONObject(thisResponse);
+                                    String sku = object.getString("productId");
+
+                                    //Log.i(TAG, "ecommerceTracker put: " + sku + " '" + String.valueOf(price_amount_micros)+"'" + " cur:"+price_currency_code);
+                                    ItemData item = new ItemData();
+                                    item.price = object.getString("price");
+                                    item.curCode = object.getString("price_currency_code");
+                                    item.micros = (float) (Double.valueOf(object.getString("price_amount_micros")) / 1000000);
+                                    prices.put(sku, item);
+
+                                } catch (JSONException e) {
+                                    e.printStackTrace();
+                                }
+                            }
+                        }
+                    }
+
+                    String[] ar = details.toArray(new String[details.size()]);
+                    nativeBillingDetails(ar);
+                } catch (RemoteException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+    }
+
+    @Override
+    public void consume(final String token) {
+        new Thread(new Runnable() {
+            public void run() {
+                if (_service == null)
+                    return;
+
+                try {
+                    Log.d(TAG, "billing.consume");
+                    int response = _service.consumePurchase(3, _activity.getPackageName(), token);
+                    if (response == 0) {
+                    }
+                } catch (RemoteException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                int i = 0;
+            }
+        }).start();
+    }
+
+    @Override
+    public void purchase(final String sku, final String payload) {
+        _activity.runOnUiThread(new Runnable() {
+            public void run() {
+                if (_service == null)
+                    return;
+
+                try {
+                    Log.d(TAG, "billing.purchase");
+                    //item = "android.test.purchased";
+                    Bundle buyIntentBundle = _service.getBuyIntent(3, _activity.getPackageName(), sku, "inapp", payload);
+                    PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
+
+                    _activity.startIntentSenderForResult(pendingIntent.getIntentSender(),
+                            BILLING_REQUEST_CODE, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                } catch (IntentSender.SendIntentException e) {
+                    e.printStackTrace();
+                } catch (NullPointerException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    class ItemData {
+        public String price;
+        public float micros;
+        public String curCode;
+    }
+}

+ 55 - 0
example/HelloWorldBilling/data/demo/big.bmfc

@@ -0,0 +1,55 @@
+# AngelCode Bitmap Font Generator configuration file
+fileVersion=1
+
+# font settings
+fontName=Arial
+fontFile=
+charSet=0
+fontSize=-26
+aa=1
+scaleH=100
+useSmoothing=1
+isBold=1
+isItalic=0
+useUnicode=1
+disableBoxChars=1
+outputInvalidCharGlyph=0
+dontIncludeKerningPairs=1
+useHinting=1
+renderFromOutline=0
+useClearType=1
+
+# character alignment
+paddingDown=0
+paddingUp=0
+paddingRight=0
+paddingLeft=0
+spacingHoriz=1
+spacingVert=1
+useFixedHeight=0
+forceZero=0
+
+# output file
+outWidth=512
+outHeight=512
+outBitDepth=32
+fontDescFormat=1
+fourChnlPacked=0
+textureFormat=png
+textureCompression=0
+alphaChnl=0
+redChnl=4
+greenChnl=4
+blueChnl=4
+invA=0
+invR=0
+invG=0
+invB=0
+
+# outline
+outlineThickness=0
+
+# selected chars
+chars=32-126,169,174,176,180
+
+# imported icon images

BIN
example/HelloWorldBilling/data/demo/button.png


BIN
example/HelloWorldBilling/data/demo/eng.txt


+ 109 - 0
example/HelloWorldBilling/data/demo/font.fnt

@@ -0,0 +1,109 @@
+<?xml version="1.0" ?><font>
+  <info aa="1" bold="1" charset="" face="Arial" italic="0" outline="0" padding="0,0,0,0" size="-26" smooth="1" spacing="1,1" stretchH="100" unicode="1"/>
+  <common alphaChnl="0" base="24" blueChnl="4" greenChnl="4" lineHeight="30" packed="0" pages="1" redChnl="4" scaleH="128" scaleW="512"/>
+  <pages>
+    <page file="font.png" id="0"/>
+  </pages>
+  <chars count="100">
+    <char chnl="15" height="1" id="32" page="0" width="3" x="98" xadvance="7" xoffset="-1" y="23" yoffset="29"/>
+    <char chnl="15" height="19" id="33" page="0" width="6" x="30" xadvance="8" xoffset="1" y="46" yoffset="5"/>
+    <char chnl="15" height="7" id="34" page="0" width="11" x="376" xadvance="12" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="19" id="35" page="0" width="16" x="108" xadvance="14" xoffset="-1" y="23" yoffset="5"/>
+    <char chnl="15" height="22" id="36" page="0" width="14" x="98" xadvance="14" xoffset="0" y="0" yoffset="4"/>
+    <char chnl="15" height="20" id="37" page="0" width="23" x="134" xadvance="24" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="38" page="0" width="19" x="323" xadvance="19" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="7" id="39" page="0" width="6" x="388" xadvance="6" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="24" id="40" page="0" width="7" x="76" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="41" page="0" width="7" x="84" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="9" id="42" page="0" width="10" x="348" xadvance="10" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="14" id="43" page="0" width="15" x="119" xadvance="15" xoffset="0" y="43" yoffset="7"/>
+    <char chnl="15" height="8" id="44" page="0" width="5" x="370" xadvance="7" xoffset="1" y="40" yoffset="20"/>
+    <char chnl="15" height="4" id="45" page="0" width="8" x="411" xadvance="9" xoffset="1" y="40" yoffset="15"/>
+    <char chnl="15" height="4" id="46" page="0" width="5" x="436" xadvance="7" xoffset="1" y="40" yoffset="20"/>
+    <char chnl="15" height="19" id="47" page="0" width="9" x="0" xadvance="7" xoffset="-1" y="46" yoffset="5"/>
+    <char chnl="15" height="19" id="48" page="0" width="14" x="424" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="49" page="0" width="10" x="493" xadvance="14" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="50" page="0" width="14" x="409" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="51" page="0" width="14" x="379" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="52" page="0" width="14" x="364" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="53" page="0" width="14" x="319" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="54" page="0" width="14" x="349" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="55" page="0" width="14" x="334" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="56" page="0" width="14" x="394" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="57" page="0" width="14" x="304" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="58" page="0" width="6" x="311" xadvance="10" xoffset="2" y="40" yoffset="10"/>
+    <char chnl="15" height="18" id="59" page="0" width="6" x="49" xadvance="10" xoffset="2" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="60" page="0" width="14" x="271" xadvance="15" xoffset="0" y="40" yoffset="8"/>
+    <char chnl="15" height="10" id="61" page="0" width="15" x="318" xadvance="15" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="62" page="0" width="14" x="211" xadvance="15" xoffset="0" y="40" yoffset="8"/>
+    <char chnl="15" height="19" id="63" page="0" width="15" x="240" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="25" id="64" page="0" width="25" x="0" xadvance="25" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="65" page="0" width="20" x="281" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="66" page="0" width="18" x="402" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="67" page="0" width="18" x="383" xadvance="19" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="68" page="0" width="18" x="421" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="69" page="0" width="15" x="224" xadvance="17" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="70" page="0" width="14" x="497" xadvance="16" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="71" page="0" width="19" x="343" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="72" page="0" width="17" x="18" xadvance="19" xoffset="1" y="26" yoffset="5"/>
+    <char chnl="15" height="19" id="73" page="0" width="6" x="504" xadvance="8" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="74" page="0" width="13" x="454" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="75" page="0" width="18" x="459" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="76" page="0" width="15" x="256" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="77" page="0" width="21" x="259" xadvance="23" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="78" page="0" width="17" x="72" xadvance="19" xoffset="1" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="79" page="0" width="20" x="302" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="80" page="0" width="17" x="90" xadvance="18" xoffset="1" y="25" yoffset="5"/>
+    <char chnl="15" height="21" id="81" page="0" width="20" x="113" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="82" page="0" width="18" x="440" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="83" page="0" width="17" x="36" xadvance="17" xoffset="0" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="84" page="0" width="16" x="125" xadvance="16" xoffset="1" y="22" yoffset="5"/>
+    <char chnl="15" height="19" id="85" page="0" width="17" x="0" xadvance="19" xoffset="1" y="26" yoffset="5"/>
+    <char chnl="15" height="19" id="86" page="0" width="19" x="363" xadvance="17" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="87" page="0" width="27" x="187" xadvance="25" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="88" page="0" width="17" x="54" xadvance="17" xoffset="0" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="89" page="0" width="18" x="478" xadvance="18" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="90" page="0" width="16" x="159" xadvance="16" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="24" id="91" page="0" width="8" x="67" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="92" page="0" width="9" x="10" xadvance="7" xoffset="-1" y="46" yoffset="5"/>
+    <char chnl="15" height="24" id="93" page="0" width="8" x="58" xadvance="9" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="10" id="94" page="0" width="13" x="334" xadvance="15" xoffset="1" y="40" yoffset="5"/>
+    <char chnl="15" height="3" id="95" page="0" width="16" x="442" xadvance="14" xoffset="-1" y="40" yoffset="26"/>
+    <char chnl="15" height="4" id="96" page="0" width="7" x="420" xadvance="9" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="14" id="97" page="0" width="14" x="151" xadvance="14" xoffset="0" y="41" yoffset="10"/>
+    <char chnl="15" height="19" id="98" page="0" width="15" x="208" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="99" page="0" width="14" x="166" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="100" page="0" width="15" x="192" xadvance="16" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="101" page="0" width="14" x="181" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="102" page="0" width="10" x="482" xadvance="9" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="103" page="0" width="15" x="176" xadvance="16" xoffset="0" y="20" yoffset="10"/>
+    <char chnl="15" height="19" id="104" page="0" width="14" x="439" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="105" page="0" width="5" x="37" xadvance="8" xoffset="2" y="45" yoffset="5"/>
+    <char chnl="15" height="24" id="106" page="0" width="9" x="48" xadvance="8" xoffset="-2" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="107" page="0" width="13" x="468" xadvance="14" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="108" page="0" width="5" x="43" xadvance="8" xoffset="2" y="45" yoffset="5"/>
+    <char chnl="15" height="14" id="109" page="0" width="22" x="79" xadvance="24" xoffset="1" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="110" page="0" width="14" x="196" xadvance="16" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="111" page="0" width="16" x="102" xadvance="16" xoffset="0" y="45" yoffset="10"/>
+    <char chnl="15" height="19" id="112" page="0" width="15" x="288" xadvance="16" xoffset="1" y="20" yoffset="10"/>
+    <char chnl="15" height="19" id="113" page="0" width="15" x="272" xadvance="16" xoffset="0" y="20" yoffset="10"/>
+    <char chnl="15" height="14" id="114" page="0" width="10" x="300" xadvance="10" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="115" page="0" width="14" x="226" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="116" page="0" width="9" x="20" xadvance="9" xoffset="0" y="46" yoffset="5"/>
+    <char chnl="15" height="14" id="117" page="0" width="14" x="241" xadvance="16" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="118" page="0" width="15" x="135" xadvance="15" xoffset="0" y="42" yoffset="10"/>
+    <char chnl="15" height="14" id="119" page="0" width="22" x="56" xadvance="21" xoffset="0" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="120" page="0" width="14" x="256" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="121" page="0" width="16" x="142" xadvance="15" xoffset="-1" y="21" yoffset="10"/>
+    <char chnl="15" height="14" id="122" page="0" width="13" x="286" xadvance="13" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="24" id="123" page="0" width="10" x="37" xadvance="10" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="124" page="0" width="5" x="92" xadvance="7" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="125" page="0" width="10" x="26" xadvance="10" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="6" id="126" page="0" width="15" x="395" xadvance="15" xoffset="0" y="40" yoffset="11"/>
+    <char chnl="15" height="19" id="169" page="0" width="21" x="237" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="174" page="0" width="21" x="215" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="8" id="176" page="0" width="10" x="359" xadvance="10" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="4" id="180" page="0" width="7" x="428" xadvance="9" xoffset="2" y="40" yoffset="5"/>
+    <char chnl="15" height="19" id="8470" page="0" width="28" x="158" xadvance="29" xoffset="1" y="0" yoffset="5"/>
+  </chars>
+</font>

BIN
example/HelloWorldBilling/data/demo/font.png


+ 6 - 0
example/HelloWorldBilling/data/demo/fonts.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<resources>
+	<set path = "demo" />
+	<bmfc_font file="main.bmfc" chars="eng.txt"/>	
+	<bmfc_font file="big.bmfc" chars="eng.txt"/>
+</resources>

BIN
example/HelloWorldBilling/data/demo/loading.png


BIN
example/HelloWorldBilling/data/demo/logo2.png


+ 55 - 0
example/HelloWorldBilling/data/demo/main.bmfc

@@ -0,0 +1,55 @@
+# AngelCode Bitmap Font Generator configuration file
+fileVersion=1
+
+# font settings
+fontName=Arial
+fontFile=
+charSet=0
+fontSize=-16
+aa=1
+scaleH=100
+useSmoothing=1
+isBold=1
+isItalic=0
+useUnicode=1
+disableBoxChars=1
+outputInvalidCharGlyph=0
+dontIncludeKerningPairs=1
+useHinting=1
+renderFromOutline=0
+useClearType=1
+
+# character alignment
+paddingDown=0
+paddingUp=0
+paddingRight=0
+paddingLeft=0
+spacingHoriz=1
+spacingVert=1
+useFixedHeight=0
+forceZero=0
+
+# output file
+outWidth=512
+outHeight=512
+outBitDepth=32
+fontDescFormat=1
+fourChnlPacked=0
+textureFormat=png
+textureCompression=0
+alphaChnl=0
+redChnl=4
+greenChnl=4
+blueChnl=4
+invA=0
+invR=0
+invG=0
+invB=0
+
+# outline
+outlineThickness=0
+
+# selected chars
+chars=32-126,169,174,176,180
+
+# imported icon images

+ 9 - 0
example/HelloWorldBilling/data/demo/res_ui.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<resources>
+	<set path = "demo" />
+	<atlas>
+		<image file="loading.png"/>		
+		<image file="logo2.png"/>		
+		<image file="button.png" cols = "3" />	
+	</atlas>	
+</resources>

+ 109 - 0
example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/big.fnt

@@ -0,0 +1,109 @@
+<?xml version="1.0" ?><font>
+  <info aa="1" bold="1" charset="" face="Arial" italic="0" outline="0" padding="0,0,0,0" size="-26" smooth="1" spacing="1,1" stretchH="100" unicode="1"/>
+  <common alphaChnl="0" base="24" blueChnl="4" greenChnl="4" lineHeight="30" packed="0" pages="1" redChnl="4" scaleH="128" scaleW="512"/>
+  <pages>
+    <page file="big_0.png" id="0"/>
+  </pages>
+  <chars count="100">
+    <char chnl="15" height="1" id="32" page="0" width="3" x="98" xadvance="7" xoffset="-1" y="23" yoffset="29"/>
+    <char chnl="15" height="19" id="33" page="0" width="6" x="30" xadvance="8" xoffset="1" y="46" yoffset="5"/>
+    <char chnl="15" height="7" id="34" page="0" width="11" x="376" xadvance="12" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="19" id="35" page="0" width="16" x="108" xadvance="14" xoffset="-1" y="23" yoffset="5"/>
+    <char chnl="15" height="22" id="36" page="0" width="14" x="98" xadvance="14" xoffset="0" y="0" yoffset="4"/>
+    <char chnl="15" height="20" id="37" page="0" width="23" x="134" xadvance="24" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="38" page="0" width="19" x="323" xadvance="19" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="7" id="39" page="0" width="6" x="388" xadvance="6" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="24" id="40" page="0" width="7" x="76" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="41" page="0" width="7" x="84" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="9" id="42" page="0" width="10" x="348" xadvance="10" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="14" id="43" page="0" width="15" x="119" xadvance="15" xoffset="0" y="43" yoffset="7"/>
+    <char chnl="15" height="8" id="44" page="0" width="5" x="370" xadvance="7" xoffset="1" y="40" yoffset="20"/>
+    <char chnl="15" height="4" id="45" page="0" width="8" x="411" xadvance="9" xoffset="1" y="40" yoffset="15"/>
+    <char chnl="15" height="4" id="46" page="0" width="5" x="436" xadvance="7" xoffset="1" y="40" yoffset="20"/>
+    <char chnl="15" height="19" id="47" page="0" width="9" x="0" xadvance="7" xoffset="-1" y="46" yoffset="5"/>
+    <char chnl="15" height="19" id="48" page="0" width="14" x="424" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="49" page="0" width="10" x="493" xadvance="14" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="50" page="0" width="14" x="409" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="51" page="0" width="14" x="379" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="52" page="0" width="14" x="364" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="53" page="0" width="14" x="319" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="54" page="0" width="14" x="349" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="55" page="0" width="14" x="334" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="56" page="0" width="14" x="394" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="57" page="0" width="14" x="304" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="58" page="0" width="6" x="311" xadvance="10" xoffset="2" y="40" yoffset="10"/>
+    <char chnl="15" height="18" id="59" page="0" width="6" x="49" xadvance="10" xoffset="2" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="60" page="0" width="14" x="271" xadvance="15" xoffset="0" y="40" yoffset="8"/>
+    <char chnl="15" height="10" id="61" page="0" width="15" x="318" xadvance="15" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="62" page="0" width="14" x="211" xadvance="15" xoffset="0" y="40" yoffset="8"/>
+    <char chnl="15" height="19" id="63" page="0" width="15" x="240" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="25" id="64" page="0" width="25" x="0" xadvance="25" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="65" page="0" width="20" x="281" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="66" page="0" width="18" x="402" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="67" page="0" width="18" x="383" xadvance="19" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="68" page="0" width="18" x="421" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="69" page="0" width="15" x="224" xadvance="17" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="70" page="0" width="14" x="497" xadvance="16" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="71" page="0" width="19" x="343" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="72" page="0" width="17" x="18" xadvance="19" xoffset="1" y="26" yoffset="5"/>
+    <char chnl="15" height="19" id="73" page="0" width="6" x="504" xadvance="8" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="74" page="0" width="13" x="454" xadvance="14" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="75" page="0" width="18" x="459" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="76" page="0" width="15" x="256" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="77" page="0" width="21" x="259" xadvance="23" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="78" page="0" width="17" x="72" xadvance="19" xoffset="1" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="79" page="0" width="20" x="302" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="80" page="0" width="17" x="90" xadvance="18" xoffset="1" y="25" yoffset="5"/>
+    <char chnl="15" height="21" id="81" page="0" width="20" x="113" xadvance="20" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="82" page="0" width="18" x="440" xadvance="19" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="83" page="0" width="17" x="36" xadvance="17" xoffset="0" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="84" page="0" width="16" x="125" xadvance="16" xoffset="1" y="22" yoffset="5"/>
+    <char chnl="15" height="19" id="85" page="0" width="17" x="0" xadvance="19" xoffset="1" y="26" yoffset="5"/>
+    <char chnl="15" height="19" id="86" page="0" width="19" x="363" xadvance="17" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="87" page="0" width="27" x="187" xadvance="25" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="88" page="0" width="17" x="54" xadvance="17" xoffset="0" y="25" yoffset="5"/>
+    <char chnl="15" height="19" id="89" page="0" width="18" x="478" xadvance="18" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="90" page="0" width="16" x="159" xadvance="16" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="24" id="91" page="0" width="8" x="67" xadvance="9" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="92" page="0" width="9" x="10" xadvance="7" xoffset="-1" y="46" yoffset="5"/>
+    <char chnl="15" height="24" id="93" page="0" width="8" x="58" xadvance="9" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="10" id="94" page="0" width="13" x="334" xadvance="15" xoffset="1" y="40" yoffset="5"/>
+    <char chnl="15" height="3" id="95" page="0" width="16" x="442" xadvance="14" xoffset="-1" y="40" yoffset="26"/>
+    <char chnl="15" height="4" id="96" page="0" width="7" x="420" xadvance="9" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="14" id="97" page="0" width="14" x="151" xadvance="14" xoffset="0" y="41" yoffset="10"/>
+    <char chnl="15" height="19" id="98" page="0" width="15" x="208" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="99" page="0" width="14" x="166" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="100" page="0" width="15" x="192" xadvance="16" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="14" id="101" page="0" width="14" x="181" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="102" page="0" width="10" x="482" xadvance="9" xoffset="0" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="103" page="0" width="15" x="176" xadvance="16" xoffset="0" y="20" yoffset="10"/>
+    <char chnl="15" height="19" id="104" page="0" width="14" x="439" xadvance="16" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="105" page="0" width="5" x="37" xadvance="8" xoffset="2" y="45" yoffset="5"/>
+    <char chnl="15" height="24" id="106" page="0" width="9" x="48" xadvance="8" xoffset="-2" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="107" page="0" width="13" x="468" xadvance="14" xoffset="1" y="20" yoffset="5"/>
+    <char chnl="15" height="19" id="108" page="0" width="5" x="43" xadvance="8" xoffset="2" y="45" yoffset="5"/>
+    <char chnl="15" height="14" id="109" page="0" width="22" x="79" xadvance="24" xoffset="1" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="110" page="0" width="14" x="196" xadvance="16" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="111" page="0" width="16" x="102" xadvance="16" xoffset="0" y="45" yoffset="10"/>
+    <char chnl="15" height="19" id="112" page="0" width="15" x="288" xadvance="16" xoffset="1" y="20" yoffset="10"/>
+    <char chnl="15" height="19" id="113" page="0" width="15" x="272" xadvance="16" xoffset="0" y="20" yoffset="10"/>
+    <char chnl="15" height="14" id="114" page="0" width="10" x="300" xadvance="10" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="115" page="0" width="14" x="226" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="116" page="0" width="9" x="20" xadvance="9" xoffset="0" y="46" yoffset="5"/>
+    <char chnl="15" height="14" id="117" page="0" width="14" x="241" xadvance="16" xoffset="1" y="40" yoffset="10"/>
+    <char chnl="15" height="14" id="118" page="0" width="15" x="135" xadvance="15" xoffset="0" y="42" yoffset="10"/>
+    <char chnl="15" height="14" id="119" page="0" width="22" x="56" xadvance="21" xoffset="0" y="45" yoffset="10"/>
+    <char chnl="15" height="14" id="120" page="0" width="14" x="256" xadvance="14" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="19" id="121" page="0" width="16" x="142" xadvance="15" xoffset="-1" y="21" yoffset="10"/>
+    <char chnl="15" height="14" id="122" page="0" width="13" x="286" xadvance="13" xoffset="0" y="40" yoffset="10"/>
+    <char chnl="15" height="24" id="123" page="0" width="10" x="37" xadvance="10" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="124" page="0" width="5" x="92" xadvance="7" xoffset="1" y="0" yoffset="5"/>
+    <char chnl="15" height="24" id="125" page="0" width="10" x="26" xadvance="10" xoffset="0" y="0" yoffset="5"/>
+    <char chnl="15" height="6" id="126" page="0" width="15" x="395" xadvance="15" xoffset="0" y="40" yoffset="11"/>
+    <char chnl="15" height="19" id="169" page="0" width="21" x="237" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="19" id="174" page="0" width="21" x="215" xadvance="19" xoffset="-1" y="0" yoffset="5"/>
+    <char chnl="15" height="8" id="176" page="0" width="10" x="359" xadvance="10" xoffset="0" y="40" yoffset="5"/>
+    <char chnl="15" height="4" id="180" page="0" width="7" x="428" xadvance="9" xoffset="2" y="40" yoffset="5"/>
+    <char chnl="15" height="19" id="8470" page="0" width="28" x="158" xadvance="29" xoffset="1" y="0" yoffset="5"/>
+  </chars>
+</font>

BIN
example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/big_0.png


+ 109 - 0
example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/main.fnt

@@ -0,0 +1,109 @@
+<?xml version="1.0" ?><font>
+  <info aa="1" bold="1" charset="" face="Arial" italic="0" outline="0" padding="0,0,0,0" size="-16" smooth="1" spacing="1,1" stretchH="100" unicode="1"/>
+  <common alphaChnl="0" base="15" blueChnl="4" greenChnl="4" lineHeight="19" packed="0" pages="1" redChnl="4" scaleH="64" scaleW="512"/>
+  <pages>
+    <page file="main_0.png" id="0"/>
+  </pages>
+  <chars count="100">
+    <char chnl="15" height="1" id="32" page="0" width="3" x="495" xadvance="4" xoffset="-1" y="13" yoffset="18"/>
+    <char chnl="15" height="12" id="33" page="0" width="4" x="205" xadvance="4" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="4" id="34" page="0" width="8" x="430" xadvance="8" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="35" page="0" width="11" x="404" xadvance="9" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="14" id="36" page="0" width="9" x="68" xadvance="9" xoffset="0" y="0" yoffset="2"/>
+    <char chnl="15" height="12" id="37" page="0" width="15" x="127" xadvance="16" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="38" page="0" width="12" x="201" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="4" id="39" page="0" width="4" x="446" xadvance="4" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="15" id="40" page="0" width="5" x="51" xadvance="5" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="15" id="41" page="0" width="5" x="57" xadvance="5" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="4" id="42" page="0" width="6" x="439" xadvance="6" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="8" id="43" page="0" width="10" x="387" xadvance="9" xoffset="0" y="13" yoffset="5"/>
+    <char chnl="15" height="5" id="44" page="0" width="4" x="425" xadvance="4" xoffset="0" y="13" yoffset="13"/>
+    <char chnl="15" height="2" id="45" page="0" width="6" x="473" xadvance="5" xoffset="0" y="13" yoffset="10"/>
+    <char chnl="15" height="2" id="46" page="0" width="4" x="485" xadvance="4" xoffset="0" y="13" yoffset="13"/>
+    <char chnl="15" height="12" id="47" page="0" width="6" x="188" xadvance="4" xoffset="-1" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="48" page="0" width="9" x="95" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="49" page="0" width="7" x="164" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="50" page="0" width="9" x="105" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="51" page="0" width="9" x="115" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="52" page="0" width="9" x="125" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="53" page="0" width="9" x="135" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="54" page="0" width="9" x="145" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="55" page="0" width="9" x="55" xadvance="9" xoffset="0" y="16" yoffset="3"/>
+    <char chnl="15" height="12" id="56" page="0" width="9" x="85" xadvance="9" xoffset="0" y="14" yoffset="3"/>
+    <char chnl="15" height="12" id="57" page="0" width="9" x="65" xadvance="9" xoffset="0" y="16" yoffset="3"/>
+    <char chnl="15" height="9" id="58" page="0" width="4" x="382" xadvance="6" xoffset="1" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="59" page="0" width="4" x="215" xadvance="6" xoffset="1" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="60" page="0" width="9" x="354" xadvance="9" xoffset="0" y="13" yoffset="5"/>
+    <char chnl="15" height="5" id="61" page="0" width="9" x="408" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="62" page="0" width="9" x="344" xadvance="9" xoffset="0" y="13" yoffset="5"/>
+    <char chnl="15" height="12" id="63" page="0" width="10" x="472" xadvance="10" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="16" id="64" page="0" width="16" x="0" xadvance="16" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="65" page="0" width="12" x="253" xadvance="11" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="66" page="0" width="12" x="240" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="67" page="0" width="12" x="227" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="68" page="0" width="12" x="292" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="69" page="0" width="11" x="416" xadvance="11" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="70" page="0" width="10" x="0" xadvance="10" xoffset="0" y="17" yoffset="3"/>
+    <char chnl="15" height="12" id="71" page="0" width="12" x="318" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="72" page="0" width="12" x="331" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="73" page="0" width="4" x="195" xadvance="4" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="74" page="0" width="8" x="155" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="75" page="0" width="12" x="279" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="76" page="0" width="10" x="428" xadvance="10" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="77" page="0" width="13" x="187" xadvance="13" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="78" page="0" width="11" x="344" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="79" page="0" width="12" x="214" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="80" page="0" width="11" x="356" xadvance="11" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="13" id="81" page="0" width="12" x="78" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="82" page="0" width="12" x="305" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="83" page="0" width="10" x="461" xadvance="11" xoffset="1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="84" page="0" width="10" x="483" xadvance="10" xoffset="1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="85" page="0" width="11" x="392" xadvance="12" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="86" page="0" width="13" x="173" xadvance="11" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="87" page="0" width="17" x="109" xadvance="15" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="88" page="0" width="11" x="380" xadvance="11" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="89" page="0" width="12" x="266" xadvance="10" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="90" page="0" width="11" x="368" xadvance="9" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="15" id="91" page="0" width="6" x="24" xadvance="5" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="92" page="0" width="6" x="505" xadvance="4" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="15" id="93" page="0" width="6" x="17" xadvance="5" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="6" id="94" page="0" width="9" x="398" xadvance="9" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="2" id="95" page="0" width="11" x="461" xadvance="9" xoffset="-1" y="13" yoffset="16"/>
+    <char chnl="15" height="2" id="96" page="0" width="4" x="480" xadvance="5" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="9" id="97" page="0" width="9" x="284" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="98" page="0" width="10" x="439" xadvance="10" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="9" id="99" page="0" width="9" x="294" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="100" page="0" width="10" x="450" xadvance="10" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="9" id="101" page="0" width="9" x="364" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="102" page="0" width="7" x="180" xadvance="5" xoffset="-1" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="103" page="0" width="10" x="11" xadvance="10" xoffset="0" y="17" yoffset="6"/>
+    <char chnl="15" height="12" id="104" page="0" width="10" x="22" xadvance="10" xoffset="0" y="16" yoffset="3"/>
+    <char chnl="15" height="12" id="105" page="0" width="4" x="200" xadvance="4" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="15" id="106" page="0" width="5" x="45" xadvance="4" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="107" page="0" width="9" x="75" xadvance="9" xoffset="0" y="15" yoffset="3"/>
+    <char chnl="15" height="12" id="108" page="0" width="4" x="210" xadvance="4" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="9" id="109" page="0" width="14" x="236" xadvance="14" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="110" page="0" width="10" x="262" xadvance="10" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="111" page="0" width="10" x="273" xadvance="10" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="112" page="0" width="10" x="33" xadvance="10" xoffset="0" y="16" yoffset="6"/>
+    <char chnl="15" height="12" id="113" page="0" width="10" x="44" xadvance="10" xoffset="0" y="16" yoffset="6"/>
+    <char chnl="15" height="9" id="114" page="0" width="7" x="374" xadvance="6" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="115" page="0" width="9" x="304" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="116" page="0" width="7" x="172" xadvance="5" xoffset="-1" y="13" yoffset="3"/>
+    <char chnl="15" height="9" id="117" page="0" width="10" x="251" xadvance="10" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="118" page="0" width="9" x="314" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="119" page="0" width="15" x="220" xadvance="13" xoffset="-1" y="13" yoffset="6"/>
+    <char chnl="15" height="9" id="120" page="0" width="9" x="324" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="12" id="121" page="0" width="10" x="494" xadvance="9" xoffset="-1" y="0" yoffset="6"/>
+    <char chnl="15" height="9" id="122" page="0" width="9" x="334" xadvance="9" xoffset="0" y="13" yoffset="6"/>
+    <char chnl="15" height="15" id="123" page="0" width="6" x="31" xadvance="6" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="15" id="124" page="0" width="4" x="63" xadvance="4" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="15" id="125" page="0" width="6" x="38" xadvance="6" xoffset="0" y="0" yoffset="3"/>
+    <char chnl="15" height="3" id="126" page="0" width="9" x="451" xadvance="9" xoffset="0" y="13" yoffset="8"/>
+    <char chnl="15" height="12" id="169" page="0" width="14" x="158" xadvance="12" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="12" id="174" page="0" width="14" x="143" xadvance="12" xoffset="-1" y="0" yoffset="3"/>
+    <char chnl="15" height="5" id="176" page="0" width="6" x="418" xadvance="6" xoffset="0" y="13" yoffset="3"/>
+    <char chnl="15" height="2" id="180" page="0" width="4" x="490" xadvance="5" xoffset="1" y="13" yoffset="3"/>
+    <char chnl="15" height="12" id="8470" page="0" width="17" x="91" xadvance="18" xoffset="1" y="0" yoffset="3"/>
+  </chars>
+</font>

BIN
example/HelloWorldBilling/data/ext/fonts.xml.ox/bmfc_font/main_0.png


+ 1 - 0
example/HelloWorldBilling/data/ext/fonts.xml.ox/meta.xml

@@ -0,0 +1 @@
+<resources version="2"><set/><bmfc_font sf="1.0" size="16"/><bmfc_font sf="1.0" size="26"/></resources>

+ 48 - 0
example/HelloWorldBilling/proj.android/AndroidManifest.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.oxygine.HelloWorldBilling"
+      android:versionCode="1"
+      android:versionName="1.0"
+      android:installLocation="auto">
+
+    <application android:label="@string/app_name"
+                 android:icon="@drawable/ic_launcher"
+                 android:allowBackup="true"
+                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+                 android:hardwareAccelerated="true" >
+
+        <activity android:name="org.oxygine.HelloWorldBilling.MainActivity"
+                  android:label="@string/app_name"
+                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+                  android:configChanges="locale|orientation|keyboardHidden" 
+                  android:screenOrientation="landscape">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+
+
+        <!--Amazon in-app-->
+        <receiver android:name = "com.amazon.device.iap.ResponseReceiver" >
+          <intent-filter>
+            <action android:name = "com.amazon.inapp.purchasing.NOTIFY"
+                    android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY" />
+          </intent-filter>
+        </receiver>
+
+    </application>
+
+
+    <uses-permission android:name="com.android.vending.BILLING"/>
+
+    <!-- Android 2.3.3 -->
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="12" />
+
+    <!-- OpenGL ES 2.0 -->
+    <uses-feature android:glEsVersion="0x00020000" /> 
+
+
+</manifest> 

+ 18 - 0
example/HelloWorldBilling/proj.android/ant.properties

@@ -0,0 +1,18 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+asset.dir=../data

+ 1 - 0
example/HelloWorldBilling/proj.android/ant_debug.bat

@@ -0,0 +1 @@
+ant debug

+ 2 - 0
example/HelloWorldBilling/proj.android/ant_debug.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+ant debug

+ 3 - 0
example/HelloWorldBilling/proj.android/build-run.bat

@@ -0,0 +1,3 @@
+call build
+call ant_debug
+call install

+ 4 - 0
example/HelloWorldBilling/proj.android/build-run.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+sh build.sh
+sh ant_debug.sh
+sh install.sh

+ 1 - 0
example/HelloWorldBilling/proj.android/build.bat

@@ -0,0 +1 @@
+ndk-build NDK_MODULE_PATH=../../../../ %*

+ 2 - 0
example/HelloWorldBilling/proj.android/build.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+ndk-build NDK_MODULE_PATH=${ROOT} $@

+ 93 - 0
example/HelloWorldBilling/proj.android/build.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This should be changed to the name of your project -->
+<project name="HelloWorldBilling" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

+ 11 - 0
example/HelloWorldBilling/proj.android/default.properties

@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must be checked in Version Control Systems.
+# 
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-12

+ 2 - 0
example/HelloWorldBilling/proj.android/install.bat

@@ -0,0 +1,2 @@
+adb install -r bin/HelloWorldBilling-debug.apk
+adb shell am start -n org.oxygine.HelloWorldBilling/org.oxygine.HelloWorldBilling.MainActivity

+ 3 - 0
example/HelloWorldBilling/proj.android/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+adb install -r bin/${PROJECT}-debug.apk
+adb shell am start -n org.oxygine.${PROJECT}/org.oxygine.${PROJECT}.MainActivity

+ 1 - 0
example/HelloWorldBilling/proj.android/jni/Android.mk

@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)

+ 5 - 0
example/HelloWorldBilling/proj.android/jni/Application.mk

@@ -0,0 +1,5 @@
+APP_STL := gnustl_static
+APP_CPPFLAGS += -fexceptions
+APP_CPPFLAGS += -frtti
+APP_CPPFLAGS += -std=c++11
+APP_ABI := armeabi-v7a

+ 24 - 0
example/HelloWorldBilling/proj.android/jni/src/Android.mk

@@ -0,0 +1,24 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := main
+
+#SDK_ROOT points to folder with SDL and oxygine-framework
+LOCAL_SRC_FILES := ../../../../../..//SDL/src/main/android/SDL_android_main.c
+
+LOCAL_SRC_FILES += ../../../src/entry_point.cpp ../../../src/example.cpp ../../../src/test.cpp 
+
+
+LOCAL_STATIC_LIBRARIES += oxygine-billing_static
+LOCAL_STATIC_LIBRARIES += oxygine-framework_static
+
+
+LOCAL_SHARED_LIBRARIES := SDL2
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+#import from NDK_MODULE_PATH defined in build.cmd
+$(call import-module, oxygine-billing) 
+$(call import-module, oxygine-framework)
+

+ 16 - 0
example/HelloWorldBilling/proj.android/project.properties

@@ -0,0 +1,16 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-12
+android.library.reference.1=../../../..//oxygine-framework/oxygine/SDL/android/lib
+android.library.reference.2=../../../..//oxygine-billing/android/billing

BIN
example/HelloWorldBilling/proj.android/res/drawable-hdpi/ic_launcher.png


BIN
example/HelloWorldBilling/proj.android/res/drawable-mdpi/ic_launcher.png


BIN
example/HelloWorldBilling/proj.android/res/drawable-xhdpi/ic_launcher.png


BIN
example/HelloWorldBilling/proj.android/res/drawable-xxhdpi/ic_launcher.png


+ 13 - 0
example/HelloWorldBilling/proj.android/res/layout/main.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+<TextView  
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    android:text="Hello World, SDLActivity"
+    />
+</LinearLayout>
+

+ 4 - 0
example/HelloWorldBilling/proj.android/res/values/strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">HelloWorldBilling</string>
+</resources>

+ 29 - 0
example/HelloWorldBilling/proj.android/src/org/oxygine/HelloWorldBilling/MainActivity.java

@@ -0,0 +1,29 @@
+package org.oxygine.HelloWorldBilling;
+
+import org.oxygine.lib.OxygineActivity;
+import org.oxygine.billing.BillingAmazon;
+import org.oxygine.billing.BillingGoogle;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+
+public class MainActivity extends OxygineActivity
+{
+	private boolean google = true;
+
+	@Override
+    protected void onCreate(Bundle savedInstanceState) {
+        PackageManager pm = getPackageManager();
+        String installer = pm.getInstallerPackageName(getPackageName());
+        if (installer == "com.amazon.venezia")
+            google = false;
+
+        //google = false;
+
+        if (google)
+            addObserver(new BillingGoogle("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAos3ihZdP/Fqw+kaWgHl+2Yrk9Y+gswF+pGY/ePQLk26iFUE4XWb/XcWq+dDWu8fxl6hqZd8RWHwc5tIo6ewlnZP4QVmAU03uTVzt7jTJl7OX+JADVB4e4tPrFEoKdvG/TtmANifqSfFoXh5SvL64E+uyvTDzbxTynzLfyUW7MCZPfn/nneO9A2xmJM/icu75HSvuUviwcMhtXFV6lOdYoYJG2VUMK8cicJ7T1w4MDrfWwpybUEjya4WTIbO4rqcBkwYDisOGpt5hnu1NI7TGEhh7QlzSbZlS25+hOBRCikfyUAOCkWI8WSZzP204FUjJRGNzUnVfQbCvlBTZdMAMKQIDAQAB"));
+        else
+            addObserver(new BillingAmazon());
+
+        super.onCreate(savedInstanceState);
+    }
+}

+ 19 - 0
example/HelloWorldBilling/proj.cmake/CMakeLists.txt

@@ -0,0 +1,19 @@
+cmake_minimum_required (VERSION 2.6)
+project (HelloWorldBilling)
+
+add_subdirectory(../../../../oxygine-framework/ oxygine-framework)
+add_definitions(${OXYGINE_DEFINITIONS})
+include_directories(${OXYGINE_INCLUDE_DIRS})
+link_directories(${OXYGINE_LIBRARY_DIRS})
+
+add_subdirectory(../../../../oxygine-billing/ oxygine-billing)
+include_directories(${OXYGINE_BILLING_INCLUDE_DIRS})
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+add_executable(HelloWorldBilling ../src/entry_point.cpp ../src/example.cpp  ../src/example.h ../src/test.h ../src/test.cpp)
+
+if (WIN32) #disable console mode for VC++
+	set_target_properties(HelloWorldBilling PROPERTIES WIN32_EXECUTABLE TRUE)
+endif(WIN32)
+
+target_link_libraries(HelloWorldBilling ${OXYGINE_CORE_LIBS} oxygine-billing)

+ 16 - 0
example/HelloWorldBilling/proj.cmake/run.sh

@@ -0,0 +1,16 @@
+#!/bin/bash
+
+mkdir build
+cd build
+
+#generate cmake project in the "build" folder
+cmake ..
+
+#build it
+make
+
+#move to working data folder with resources
+cd ../../data
+
+#run executable
+./../proj.cmake/build/${PROJECT}

+ 25 - 0
example/HelloWorldBilling/proj.emscripten/CMakeLists.txt

@@ -0,0 +1,25 @@
+cmake_minimum_required (VERSION 2.6)
+project (HelloWorldBilling)
+
+add_subdirectory(../../../../oxygine-framework/ oxygine-framework)
+add_definitions(${OXYGINE_DEFINITIONS})
+include_directories(${OXYGINE_INCLUDE_DIRS})
+link_directories(${OXYGINE_LIBRARY_DIRS})
+
+SET(CMAKE_EXECUTABLE_SUFFIX ".html")
+set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-warn-absolute-paths -std=c++11")
+
+add_executable(HelloWorldBilling ../src/entry_point.cpp ../src/example.cpp  ../src/example.h )
+
+if (CMAKE_BUILD_TYPE STREQUAL Debug)
+	SET(linkFlags "-g4 ")
+else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled.
+	SET(linkFlags "-O2 ")
+endif()
+
+set(linkFlags "${linkFlags} -s NO_EXIT_RUNTIME=1 -s FULL_ES2=1 -s WARN_ON_UNDEFINED_SYMBOLS=1 --memory-init-file 0 -Wno-warn-absolute-paths -s TOTAL_MEMORY=50331648")
+
+set_target_properties(HelloWorldBilling PROPERTIES LINK_FLAGS "${linkFlags}")
+
+target_link_libraries(HelloWorldBilling ${OXYGINE_CORE_LIBS})
+em_link_pre_js(HelloWorldBilling  ${OXYGINE_JS_LIBRARIES}  ${CMAKE_CURRENT_SOURCE_DIR}/data.js)

+ 7 - 0
example/HelloWorldBilling/proj.emscripten/build.bat

@@ -0,0 +1,7 @@
+python ../../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
+
+mkdir build
+cd build
+cmake -DCMAKE_TOOLCHAIN_FILE="%EMSCRIPTEN%/cmake/Modules/Platform/emscripten.cmake" -G"Unix Makefiles" .. 
+make
+cd ..

+ 7 - 0
example/HelloWorldBilling/proj.emscripten/build_release.bat

@@ -0,0 +1,7 @@
+python ../../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
+
+mkdir build_release
+cd build_release
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="%EMSCRIPTEN%/cmake/Modules/Platform/emscripten.cmake" -G"Unix Makefiles" .. 
+make
+cd ..

+ 51 - 0
example/HelloWorldBilling/proj.ios/HelloWorldBilling/HelloWorldBilling_ios-Info.plist

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIcons</key>
+	<dict/>
+	<key>CFBundleIcons~ipad</key>
+	<dict/>
+	<key>CFBundleIdentifier</key>
+	<string>oxygine.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIStatusBarHidden</key>
+	<true/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>

+ 53 - 0
example/HelloWorldBilling/proj.ios/HelloWorldBilling/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,53 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "60x60"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "1x",
+      "size" : "76x76"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "2x",
+      "size" : "76x76"
+    },
+    {
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "40x40"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "1x",
+      "size" : "40x40"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "2x",
+      "size" : "40x40"
+    },
+    {
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "1x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "2x",
+      "size" : "29x29"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 49 - 0
example/HelloWorldBilling/proj.ios/HelloWorldBilling/Images.xcassets/LaunchImage.launchimage/Contents.json

@@ -0,0 +1,49 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "minimum-system-version" : "7.0",
+      "subtype" : "retina4",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 51 - 0
example/HelloWorldBilling/proj.ios/HelloWorldBilling/LaunchImage.launchimage/Contents.json

@@ -0,0 +1,51 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 465 - 0
example/HelloWorldBilling/proj.ios/HelloWorldBilling_ios.xcodeproj/project.pbxproj

@@ -0,0 +1,465 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		048AD0AE197D24AB001963EF /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 048AD0AD197D24AB001963EF /* CoreMotion.framework */; };
+		04998D3617F8A97D003441C3 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998D3517F8A96E003441C3 /* libSDL2.a */; };
+		04998EE617F8ADB4003441C3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE117F8ADB4003441C3 /* libz.dylib */; };
+		04998EE717F8ADB4003441C3 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE217F8ADB4003441C3 /* QuartzCore.framework */; };
+		04998EE817F8ADB4003441C3 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE317F8ADB4003441C3 /* AudioToolbox.framework */; };
+		04998EE917F8ADB4003441C3 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE417F8ADB4003441C3 /* CoreAudio.framework */; };
+		04998EE917F8ADB4003441C3 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE417F8ADB4003441C3 /* CoreAudio.framework */; };
+		04998EEA17F8ADB4003441C3 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EE517F8ADB4003441C3 /* OpenGLES.framework */; };
+		04998EEE17F8ADD4003441C3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EEB17F8ADD4003441C3 /* UIKit.framework */; };
+		04998EEF17F8ADD4003441C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EEC17F8ADD4003441C3 /* Foundation.framework */; };
+		04998EF017F8ADD4003441C3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EED17F8ADD4003441C3 /* CoreGraphics.framework */; };
+		04998EF717F8B6F3003441C3 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EF517F8B6F3003441C3 /* libpng.a */; };
+		04998EF817F8B6F3003441C3 /* libjpeg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04998EF617F8B6F3003441C3 /* libjpeg.a */; };
+		049B52B11871EBFA00EF3C66 /* liboxygine_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 049B52AD1871EBBA00EF3C66 /* liboxygine_ios.a */; };
+		04E9AD3F1876FE84006A7317 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04E9AD3E1876FE84006A7317 /* Images.xcassets */; };
+		2DC477AC10D6C07B3FE008F6 /* ../src/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */; };
+		DA49ED8903C628BA578C8670 /* ../src/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */; };
+		C8860D93875589970329DCCD /* ../data/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DA100C319512824B7570663 /* ../data/entry_point.cpp */; };
+		1E839D002B2BA83FC83A695A /* ../data/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/example.cpp */; };
+		3A631A475DE035FC53ADE5EA /* ../data/example.h in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/example.h */; };
+
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		04998D3417F8A96E003441C3 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04998D2F17F8A96E003441C3 /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = FD6526630DE8FCCB002AD96B;
+			remoteInfo = libSDL;
+		};
+		04998D3717F8A982003441C3 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04998D2F17F8A96E003441C3 /* SDL.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = FD6526620DE8FCCB002AD96B;
+			remoteInfo = libSDL;
+		};
+		049B52AC1871EBBA00EF3C66 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = C3E86F4C16EBC8A500052915;
+			remoteInfo = oxygine_ios;
+		};
+		049B52AF1871EBD100EF3C66 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = C3E86F4B16EBC8A500052915;
+			remoteInfo = oxygine_ios;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		04998CEC17F8A933003441C3 /* HelloWorldBilling_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorldBilling_ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		04998D2F17F8A96E003441C3 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = "../../../..//SDL/Xcode-iOS/SDL/SDL.xcodeproj"; sourceTree = "<group>"; };
+		04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_ios.xcodeproj; path = "../../../../oxygine-framework//oxygine/SDL/ios/oxygine/oxygine_ios.xcodeproj"; sourceTree = "<group>"; };
+		04998EE117F8ADB4003441C3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		04998EE217F8ADB4003441C3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		04998EE317F8ADB4003441C3 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
+		04998EE417F8ADB4003441C3 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
+		048AD0AD197D24AB001963EF /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; };
+		04998EE517F8ADB4003441C3 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
+		04998EEB17F8ADD4003441C3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		04998EEC17F8ADD4003441C3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		04998EED17F8ADD4003441C3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		04998EF517F8B6F3003441C3 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a"; sourceTree = "<group>"; };
+		04998EF617F8B6F3003441C3 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = "../../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a"; sourceTree = "<group>"; };
+		04E9AD3E1876FE84006A7317 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name =Images.xcassets; path = HelloWorldBilling/Images.xcassets; sourceTree = "<group>"; };
+		360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../src/entry_point.cpp; sourceTree = "<group>"; };
+		0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
+		F6123B1E6FE4471A00F49751 /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
+		4DA100C319512824B7570663 /* ../data/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../data/entry_point.cpp; sourceTree = "<group>"; };
+		04FE4D4FB640E0DF92DFB865 /* ../data/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../data/example.cpp; sourceTree = "<group>"; };
+		7F3B12E3C9D554D9FE28101D /* ../data/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../data/example.h; sourceTree = "<group>"; };
+
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		04998CE917F8A933003441C3 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				049B52B11871EBFA00EF3C66 /* liboxygine_ios.a in Frameworks */,
+				04998D3617F8A97D003441C3 /* libSDL2.a in Frameworks */,
+				04998EF017F8ADD4003441C3 /* CoreGraphics.framework in Frameworks */,
+				048AD0AE197D24AB001963EF /* CoreMotion.framework in Frameworks */,
+				04998EEF17F8ADD4003441C3 /* Foundation.framework in Frameworks */,
+				04998EE617F8ADB4003441C3 /* libz.dylib in Frameworks */,
+				04998EE917F8ADB4003441C3 /* CoreAudio.framework in Frameworks */,
+				04998EF817F8B6F3003441C3 /* libjpeg.a in Frameworks */,
+				04998EEE17F8ADD4003441C3 /* UIKit.framework in Frameworks */,
+				04998EE817F8ADB4003441C3 /* AudioToolbox.framework in Frameworks */,
+				04998EE717F8ADB4003441C3 /* QuartzCore.framework in Frameworks */,
+				04998EEA17F8ADB4003441C3 /* OpenGLES.framework in Frameworks */,
+				04998EF717F8B6F3003441C3 /* libpng.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		045D531C17F8BD5E00CC2C64 /* dependencies */ = {
+			isa = PBXGroup;
+			children = (
+				04998EE117F8ADB4003441C3 /* libz.dylib */,
+				04998EF617F8B6F3003441C3 /* libjpeg.a */,
+				04998EF517F8B6F3003441C3 /* libpng.a */,
+			);
+			name = dependencies;
+			sourceTree = "<group>";
+		};
+		04998CE317F8A933003441C3 = {
+			isa = PBXGroup;
+			children = (
+				045D531C17F8BD5E00CC2C64 /* dependencies */,
+				04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */,
+				04998D2F17F8A96E003441C3 /* SDL.xcodeproj */,
+				04998D4417F8A9ED003441C3 /* src */,
+				04E9AD3E1876FE84006A7317 /* Images.xcassets */,
+				04998CF617F8A933003441C3 /* Supporting Files */,
+				04998CEE17F8A933003441C3 /* Frameworks */,
+				04998CED17F8A933003441C3 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		04998CED17F8A933003441C3 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				04998CEC17F8A933003441C3 /* HelloWorldBilling_ios.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		04998CEE17F8A933003441C3 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				04998EEB17F8ADD4003441C3 /* UIKit.framework */,
+				048AD0AD197D24AB001963EF /* CoreMotion.framework */,
+				04998EEC17F8ADD4003441C3 /* Foundation.framework */,
+				04998EED17F8ADD4003441C3 /* CoreGraphics.framework */,
+				04998EE217F8ADB4003441C3 /* QuartzCore.framework */,
+				04998EE317F8ADB4003441C3 /* AudioToolbox.framework */,
+				04998EE417F8ADB4003441C3 /* CoreAudio.framework */,
+				04998EE517F8ADB4003441C3 /* OpenGLES.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+
+		04998CF617F8A933003441C3 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				4DA100C319512824B7570663 /* entry_point.cpp */, 
+				04FE4D4FB640E0DF92DFB865 /* example.cpp */, 
+				7F3B12E3C9D554D9FE28101D /* example.h */, 
+
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		04998D3017F8A96E003441C3 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				04998D3517F8A96E003441C3 /* libSDL2.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		04998D4417F8A9ED003441C3 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				360377333740D8A2FD15BBE6 /* entry_point.cpp */, 
+				0BF9628FC8D38F9748F0CDEB /* example.cpp */, 
+				F6123B1E6FE4471A00F49751 /* example.h */, 
+
+			);
+			name = src;
+			sourceTree = "<group>";
+		};
+		049B52A91871EBBA00EF3C66 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				049B52AD1871EBBA00EF3C66 /* liboxygine_ios.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		04998CEB17F8A933003441C3 /* HelloWorldBilling_ios */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloWorldBilling_ios" */;
+			buildPhases = (
+				04998CE817F8A933003441C3 /* Sources */,
+				04998CE917F8A933003441C3 /* Frameworks */,
+				04998CEA17F8A933003441C3 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				04998D3817F8A982003441C3 /* PBXTargetDependency */,
+				049B52B01871EBD100EF3C66 /* PBXTargetDependency */,
+			);
+			name = HelloWorldBilling_ios;
+			productName = HelloWorldBilling;
+			productReference = 04998CEC17F8A933003441C3 /* HelloWorldBilling_ios.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		04998CE417F8A933003441C3 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0510;
+				ORGANIZATIONNAME = Mac;
+			};
+			buildConfigurationList = 04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloWorldBilling_ios" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 04998CE317F8A933003441C3;
+			productRefGroup = 04998CED17F8A933003441C3 /* Products */;
+			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = 049B52A91871EBBA00EF3C66 /* Products */;
+					ProjectRef = 04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */;
+				},
+				{
+					ProductGroup = 04998D3017F8A96E003441C3 /* Products */;
+					ProjectRef = 04998D2F17F8A96E003441C3 /* SDL.xcodeproj */;
+				},
+			);
+			projectRoot = "";
+			targets = (
+				04998CEB17F8A933003441C3 /* HelloWorldBilling_ios */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+		04998D3517F8A96E003441C3 /* libSDL2.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDL2.a;
+			remoteRef = 04998D3417F8A96E003441C3 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		049B52AD1871EBBA00EF3C66 /* liboxygine_ios.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = liboxygine_ios.a;
+			remoteRef = 049B52AC1871EBBA00EF3C66 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		04998CEA17F8A933003441C3 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				04E9AD3F1876FE84006A7317 /* Images.xcassets in Resources */,
+				C8860D93875589970329DCCD /* entry_point.cpp */, 
+				1E839D002B2BA83FC83A695A /* example.cpp */, 
+				3A631A475DE035FC53ADE5EA /* example.h */, 
+
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		04998CE817F8A933003441C3 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2DC477AC10D6C07B3FE008F6 /* entry_point.cpp */, 
+				DA49ED8903C628BA578C8670 /* example.cpp */, 
+
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		04998D3817F8A982003441C3 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = libSDL;
+			targetProxy = 04998D3717F8A982003441C3 /* PBXContainerItemProxy */;
+		};
+		049B52B01871EBD100EF3C66 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = oxygine_ios;
+			targetProxy = 049B52AF1871EBD100EF3C66 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		04998D1F17F8A933003441C3 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COMPRESS_PNG_FILES = NO;
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				ONLY_ACTIVE_ARCH = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
+			};
+			name = Debug;
+		};
+		04998D2017F8A933003441C3 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COMPRESS_PNG_FILES = NO;
+				COPY_PHASE_STRIP = YES;
+				ENABLE_NS_ASSERTIONS = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		04998D2217F8A933003441C3 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "HelloWorldBilling/HelloWorldBilling_ios-Prefix.pch";
+				GCC_WARN_UNUSED_VALUE = YES;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				INFOPLIST_FILE = "HelloWorldBilling/HelloWorldBilling_ios-Info.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
+				);
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_NAME = HelloWorldBilling_ios;
+				PROVISIONING_PROFILE = "A34F5D84-E1EB-47B5-AD4B-67D0FA4A5BE6";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		04998D2317F8A933003441C3 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "HelloWorldBilling/HelloWorldBilling_ios-Prefix.pch";
+				GCC_WARN_UNUSED_VALUE = YES;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				INFOPLIST_FILE = "HelloWorldBilling/HelloWorldBilling_ios-Info.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
+				);
+				ONLY_ACTIVE_ARCH = NO;
+				PRODUCT_NAME = HelloWorldBilling_ios;
+				PROVISIONING_PROFILE = "A34F5D84-E1EB-47B5-AD4B-67D0FA4A5BE6";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloWorldBilling_ios" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				04998D1F17F8A933003441C3 /* Debug */,
+				04998D2017F8A933003441C3 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloWorldBilling_ios" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				04998D2217F8A933003441C3 /* Debug */,
+				04998D2317F8A933003441C3 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 04998CE417F8A933003441C3 /* Project object */;
+}

+ 58 - 0
example/HelloWorldBilling/proj.macosx/HelloWorldBilling/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,58 @@
+{
+  "images" : [
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 34 - 0
example/HelloWorldBilling/proj.macosx/HelloWorldBilling_macosx-Info.plist

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>oxygine.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2013 oxygine. All rights reserved.</string>
+	<key>NSMainNibFile</key>
+	<string>MainMenu</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>

+ 491 - 0
example/HelloWorldBilling/proj.macosx/HelloWorldBilling_macosx.xcodeproj/project.pbxproj

@@ -0,0 +1,491 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		04059FEA1872027500BA6557 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04A57D861872012D0068B1E5 /* SDL2.framework */; };
+		04059FEB1872027B00BA6557 /* liboxygine_macosx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04059FE41872026200BA6557 /* liboxygine_macosx.a */; };
+		04059FED187202A200BA6557 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 04059FEC187202A200BA6557 /* libz.dylib */; };
+		04059FEF187202AC00BA6557 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04059FEE187202AC00BA6557 /* OpenGL.framework */; };
+		0405A00018720D2200BA6557 /* libjpeg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04059FF01872031A00BA6557 /* libjpeg.a */; };
+		0405A00118720D2200BA6557 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04059FF11872031A00BA6557 /* libpng.a */; };
+		049B57321871FBE900EF3C66 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 049B57311871FBE900EF3C66 /* Cocoa.framework */; };
+		049B574A1871FBE900EF3C66 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 049B57491871FBE900EF3C66 /* Images.xcassets */; };
+		2DC477AC10D6C07B3FE008F6 /* ../src/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */; };
+		DA49ED8903C628BA578C8670 /* ../src/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */; };
+		C8860D93875589970329DCCD /* ../data/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DA100C319512824B7570663 /* ../data/entry_point.cpp */; };
+		1E839D002B2BA83FC83A695A /* ../data/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/example.cpp */; };
+		3A631A475DE035FC53ADE5EA /* ../data/example.h in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/example.h */; };
+
+		
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		04059FE31872026200BA6557 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 049B52BB1871EDE900EF3C66;
+			remoteInfo = oxygine_macosx;
+		};
+		04059FE81872027200BA6557 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 049B52BA1871EDE900EF3C66;
+			remoteInfo = oxygine_macosx;
+		};
+		04A57D851872012D0068B1E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = BECDF66C0761BA81005FE872;
+			remoteInfo = Framework;
+		};
+		04A57D871872012D0068B1E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = BECDF6B30761BA81005FE872;
+			remoteInfo = "Static Library";
+		};
+		04A57D891872012D0068B1E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = DB31407717554B71006C0E22;
+			remoteInfo = "Shared Library";
+		};
+		04A57D8B1872012D0068B1E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = BECDF6BE0761BA81005FE872;
+			remoteInfo = "Standard DMG";
+		};
+		04A57D8E187201EF0068B1E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = BECDF5FE0761BA81005FE872;
+			remoteInfo = Framework;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		04059FEC187202A200BA6557 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		04059FEE187202AC00BA6557 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		04059FF01872031A00BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../../oxygine-framework//oxygine/third_party/macosx/libraries/libjpeg.a; sourceTree = "<group>"; };
+		04059FF11872031A00BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../../oxygine-framework//oxygine/third_party/macosx/libraries/libpng.a; sourceTree = "<group>"; };
+		04059FF4187203A600BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a; sourceTree = "<group>"; };
+		04059FF5187203A600BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a; sourceTree = "<group>"; };
+		049B572E1871FBE900EF3C66 /* demo_macosx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorldBilling_macosx.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		049B57311871FBE900EF3C66 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+		049B57341871FBE900EF3C66 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
+		049B57351871FBE900EF3C66 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
+		049B57361871FBE900EF3C66 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		049B57391871FBE900EF3C66 /* demo_macosx-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HelloWorldBilling_macosx-Info.plist"; sourceTree = "<group>"; };
+		049B57491871FBE900EF3C66 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HelloWorldBilling/Images.xcassets; sourceTree = "<group>"; };
+		049B57501871FBE900EF3C66 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
+		360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../src/entry_point.cpp; sourceTree = "<group>"; };
+		0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
+		F6123B1E6FE4471A00F49751 /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
+		4DA100C319512824B7570663 /* ../data/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../data/entry_point.cpp; sourceTree = "<group>"; };
+		04FE4D4FB640E0DF92DFB865 /* ../data/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../data/example.cpp; sourceTree = "<group>"; };
+		7F3B12E3C9D554D9FE28101D /* ../data/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../data/example.h; sourceTree = "<group>"; };
+
+		04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_macosx.xcodeproj; path = ../../../../oxygine-framework//oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj; sourceTree = "<group>"; };
+		04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../../../..//SDL/Xcode/SDL/SDL.xcodeproj; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		049B572B1871FBE900EF3C66 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				0405A00018720D2200BA6557 /* libjpeg.a in Frameworks */,
+				0405A00118720D2200BA6557 /* libpng.a in Frameworks */,
+				04059FEF187202AC00BA6557 /* OpenGL.framework in Frameworks */,
+				04059FED187202A200BA6557 /* libz.dylib in Frameworks */,
+				04059FEB1872027B00BA6557 /* liboxygine_macosx.a in Frameworks */,
+				04059FEA1872027500BA6557 /* SDL2.framework in Frameworks */,
+				049B57321871FBE900EF3C66 /* Cocoa.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		04059FE01872026200BA6557 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				04059FE41872026200BA6557 /* liboxygine_macosx.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		049B57251871FBE900EF3C66 = {
+			isa = PBXGroup;
+			children = (
+				049B57491871FBE900EF3C66 /* Images.xcassets */,
+				049B57381871FBE900EF3C66 /* Supporting Files */,
+				04A57D391871FF8B0068B1E5 /* src */,
+				04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */,
+				04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */,
+				049B57301871FBE900EF3C66 /* Frameworks */,
+				049B572F1871FBE900EF3C66 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		049B572F1871FBE900EF3C66 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				049B572E1871FBE900EF3C66 /* HelloWorldBilling_macosx.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		049B57301871FBE900EF3C66 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				04059FF4187203A600BA6557 /* libjpeg.a */,
+				04059FF5187203A600BA6557 /* libpng.a */,
+				04059FF01872031A00BA6557 /* libjpeg.a */,
+				04059FF11872031A00BA6557 /* libpng.a */,
+				04059FEE187202AC00BA6557 /* OpenGL.framework */,
+				04059FEC187202A200BA6557 /* libz.dylib */,
+				049B57311871FBE900EF3C66 /* Cocoa.framework */,
+				049B57501871FBE900EF3C66 /* XCTest.framework */,
+				049B57331871FBE900EF3C66 /* Other Frameworks */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		049B57331871FBE900EF3C66 /* Other Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				049B57341871FBE900EF3C66 /* AppKit.framework */,
+				049B57351871FBE900EF3C66 /* CoreData.framework */,
+				049B57361871FBE900EF3C66 /* Foundation.framework */,
+			);
+			name = "Other Frameworks";
+			sourceTree = "<group>";
+		};
+		049B57371871FBE900EF3C66 /* demo */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = demo;
+			sourceTree = "<group>";
+		};
+		049B57381871FBE900EF3C66 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				4DA100C319512824B7570663 /* entry_point.cpp */, 
+				04FE4D4FB640E0DF92DFB865 /* example.cpp */, 
+				7F3B12E3C9D554D9FE28101D /* example.h */, 
+
+				049B57391871FBE900EF3C66 /* HelloWorldBilling_macosx-Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		04A57D391871FF8B0068B1E5 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				360377333740D8A2FD15BBE6 /* entry_point.cpp */, 
+				0BF9628FC8D38F9748F0CDEB /* example.cpp */, 
+				F6123B1E6FE4471A00F49751 /* example.h */, 
+
+			);
+			name = src;
+			sourceTree = "<group>";
+		};
+		04A57D7F1872012A0068B1E5 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				04A57D861872012D0068B1E5 /* SDL2.framework */,
+				04A57D881872012D0068B1E5 /* libSDL2.a */,
+				04A57D8A1872012D0068B1E5 /* libSDL2.dylib */,
+				04A57D8C1872012D0068B1E5 /* Standard DMG */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		049B572D1871FBE900EF3C66 /* HelloWorldBilling_macosx */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloWorldBilling_macosx" */;
+			buildPhases = (
+				049B572A1871FBE900EF3C66 /* Sources */,
+				049B572B1871FBE900EF3C66 /* Frameworks */,
+				049B572C1871FBE900EF3C66 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				04059FE91872027200BA6557 /* PBXTargetDependency */,
+				04A57D8F187201EF0068B1E5 /* PBXTargetDependency */,
+			);
+			name = HelloWorldBilling_macosx;
+			productName = HelloWorldBilling;
+			productReference = 049B572E1871FBE900EF3C66 /* HelloWorldBilling_macosx.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		049B57261871FBE900EF3C66 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0610;
+				ORGANIZATIONNAME = oxygine;
+			};
+			buildConfigurationList = 049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloWorldBilling_macosx" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 049B57251871FBE900EF3C66;
+			productRefGroup = 049B572F1871FBE900EF3C66 /* Products */;
+			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = 04059FE01872026200BA6557 /* Products */;
+					ProjectRef = 04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */;
+				},
+				{
+					ProductGroup = 04A57D7F1872012A0068B1E5 /* Products */;
+					ProjectRef = 04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */;
+				},
+			);
+			projectRoot = "";
+			targets = (
+				049B572D1871FBE900EF3C66 /* HelloWorldBilling_macosx */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+		04059FE41872026200BA6557 /* liboxygine_macosx.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = liboxygine_macosx.a;
+			remoteRef = 04059FE31872026200BA6557 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		04A57D861872012D0068B1E5 /* SDL2.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = SDL2.framework;
+			remoteRef = 04A57D851872012D0068B1E5 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		04A57D881872012D0068B1E5 /* libSDL2.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDL2.a;
+			remoteRef = 04A57D871872012D0068B1E5 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		04A57D8A1872012D0068B1E5 /* libSDL2.dylib */ = {
+			isa = PBXReferenceProxy;
+			fileType = "compiled.mach-o.dylib";
+			path = libSDL2.dylib;
+			remoteRef = 04A57D891872012D0068B1E5 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		04A57D8C1872012D0068B1E5 /* Standard DMG */ = {
+			isa = PBXReferenceProxy;
+			fileType = "compiled.mach-o.executable";
+			path = "Standard DMG";
+			remoteRef = 04A57D8B1872012D0068B1E5 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		049B572C1871FBE900EF3C66 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C8860D93875589970329DCCD /* entry_point.cpp */, 
+				1E839D002B2BA83FC83A695A /* example.cpp */, 
+				3A631A475DE035FC53ADE5EA /* example.h */, 
+
+				049B574A1871FBE900EF3C66 /* Images.xcassets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		049B572A1871FBE900EF3C66 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2DC477AC10D6C07B3FE008F6 /* entry_point.cpp */, 
+				DA49ED8903C628BA578C8670 /* example.cpp */, 
+
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		04059FE91872027200BA6557 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = oxygine_macosx;
+			targetProxy = 04059FE81872027200BA6557 /* PBXContainerItemProxy */;
+		};
+		04A57D8F187201EF0068B1E5 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = Framework;
+			targetProxy = 04A57D8E187201EF0068B1E5 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		049B575D1871FBE900EF3C66 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_OBJC_ARC = NO;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.8;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
+				VALID_ARCHS = "x86_64";
+			};
+			name = Debug;
+		};
+		049B575E1871FBE900EF3C66 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_OBJC_ARC = NO;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.8;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
+				VALID_ARCHS = "x86_64";
+			};
+			name = Release;
+		};
+		049B57601871FBE900EF3C66 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "HelloWorldBilling/HelloWorldBilling_macosx-Prefix.pch";
+				INFOPLIST_FILE = "HelloWorldBilling_macosx-Info.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"../../../../oxygine-framework//oxygine/third_party/macosx/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
+				);
+				PRODUCT_NAME = HelloWorldBilling_macosx;
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		049B57611871FBE900EF3C66 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "HelloWorldBilling/HelloWorldBilling_macosx-Prefix.pch";
+				INFOPLIST_FILE = "HelloWorldBilling_macosx-Info.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"../../../../oxygine-framework//oxygine/third_party/macosx/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
+				);
+				PRODUCT_NAME = HelloWorldBilling_macosx;
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloWorldBilling_macosx" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				049B575D1871FBE900EF3C66 /* Debug */,
+				049B575E1871FBE900EF3C66 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloWorldBilling_macosx" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				049B57601871FBE900EF3C66 /* Debug */,
+				049B57611871FBE900EF3C66 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 049B57261871FBE900EF3C66 /* Project object */;
+}

+ 48 - 0
example/HelloWorldBilling/proj.win32/HelloWorldBilling.sln

@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldBilling", "HelloWorldBilling.vcxproj", "{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oxygine", "../../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj", "{52411305-CFE1-4FA8-9885-5729BFC816CF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Debug|Win32.Build.0 = Debug|Win32
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Debug|x64.ActiveCfg = Debug|Win32
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Release|Win32.ActiveCfg = Release|Win32
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Release|Win32.Build.0 = Release|Win32
+		{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}.Release|x64.ActiveCfg = Release|Win32
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.ActiveCfg = Debug|Win32
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.Build.0 = Debug|Win32
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.ActiveCfg = Debug|x64
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.Build.0 = Debug|x64
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.ActiveCfg = Release|Win32
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.Build.0 = Release|Win32
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.ActiveCfg = Release|x64
+		{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.Build.0 = Release|x64
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|Win32.Build.0 = Debug|Win32
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|x64.ActiveCfg = Debug|x64
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|x64.Build.0 = Debug|x64
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|Win32.ActiveCfg = Release|Win32
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|Win32.Build.0 = Release|Win32
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|x64.ActiveCfg = Release|x64
+		{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|x64.Build.0 = Release|x64
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Debug|Win32.Build.0 = Debug|Win32
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Debug|x64.ActiveCfg = Debug|Win32
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Release|Win32.ActiveCfg = Release|Win32
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Release|Win32.Build.0 = Release|Win32
+		{52411305-CFE1-4FA8-9885-5729BFC816CF}.Release|x64.ActiveCfg = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 128 - 0
example/HelloWorldBilling/proj.win32/HelloWorldBilling.vcxproj

@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>HelloWorldBilling</RootNamespace>
+    <ProjectName>HelloWorldBilling</ProjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '10.0'">v100</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '11.0'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '11.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v110_xp</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v120_xp</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '10.0'">v100</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '11.0'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '11.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v110_xp</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v120_xp</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)_$(PlatformToolset)\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)_$(PlatformToolset)\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)_$(PlatformToolset)\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)_$(PlatformToolset)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>../../../../oxygine-framework//oxygine/src;../../../..//SDL/include;../../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;../../../../oxygine-billing/src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>libcurl_imp.lib;libjpeg.lib;libpng.lib;libzlib.lib;opengl32.lib;pthreadVCE2.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies Condition="'$(VisualStudioVersion)' == '14.0'">libcurl_imp.lib;libjpeg-2015.lib;libpng-2015.lib;libzlib.lib;opengl32.lib;pthreadVCE2.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>../../../../oxygine-framework//oxygine/src;../../../..//SDL/include;../../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;../../../../oxygine-billing/src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalLibraryDirectories>../../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>libcurl_imp.lib;libjpeg.lib;libpng.lib;libzlib.lib;opengl32.lib;pthreadVCE2.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies Condition="'$(VisualStudioVersion)' == '14.0'">libcurl_imp.lib;libjpeg-2015.lib;libpng-2015.lib;libzlib.lib;opengl32.lib;pthreadVCE2.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ProjectReference Include="../../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj">
+      <Project>{52411305-cfe1-4fa8-9885-5729bfc816cf}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="../src/entry_point.cpp" />
+    <ClCompile Include="../src/example.cpp" />
+    <ClCompile Include="../src/test.cpp" />
+    <ClCompile Include="..\..\..\src\billing.cpp" />
+    <ClCompile Include="..\..\..\src\sim\BillingSimulator.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="../src/example.h" />
+    <ClInclude Include="../src/test.h" />
+    <ClInclude Include="..\..\..\src\billing.h" />
+    <ClInclude Include="..\..\..\src\sim\BillingSimulator.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 54 - 0
example/HelloWorldBilling/proj.win32/HelloWorldBilling.vcxproj.filters

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="billing">
+      <UniqueIdentifier>{2439318a-dc8e-4b56-b1a0-b24cca591dbe}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="billing\sim">
+      <UniqueIdentifier>{e69d4fcb-37ea-4356-88a9-907c0f7ebaaa}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="../src/entry_point.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="../src/example.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="../src/test.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\src\billing.cpp">
+      <Filter>billing</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\src\sim\BillingSimulator.cpp">
+      <Filter>billing\sim</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="../src/example.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="../src/test.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\billing.h">
+      <Filter>billing</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\sim\BillingSimulator.h">
+      <Filter>billing\sim</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 151 - 0
example/HelloWorldBilling/src/entry_point.cpp

@@ -0,0 +1,151 @@
+/**
+Attention!
+This file has Oxygine initialization stuff.
+If you just started you don't need to understand it exactly you could check it later.
+You could start from example.cpp and example.h it has main functions being called from there
+*/
+#include "core/oxygine.h"
+#include "Stage.h"
+#include "DebugActor.h"
+
+#include "example.h"
+
+
+using namespace oxygine;
+
+
+//called each frame
+int mainloop()
+{
+    example_update();
+    //update our stage
+    //update all actors. Actor::update would be called also for all children
+    getStage()->update();
+
+    if (core::beginRendering())
+    {
+        Color clearColor(32, 32, 32, 255);
+        Rect viewport(Point(0, 0), core::getDisplaySize());
+        //render all actors. Actor::render would be called also for all children
+        getStage()->render(clearColor, viewport);
+
+        core::swapDisplayBuffers();
+    }
+
+    //update internal components
+    //all input events would be passed to Stage::instance.handleEvent
+    //if done is true then User requests quit from app.
+    bool done = core::update();
+
+    return done ? 1 : 0;
+}
+
+//it is application entry point
+void run()
+{
+    ObjectBase::__startTracingLeaks();
+
+    //initialize Oxygine's internal stuff
+    core::init_desc desc;
+
+#if OXYGINE_SDL || OXYGINE_EMSCRIPTEN
+    //we could setup initial window size on SDL builds
+    desc.w = 960;
+    desc.h = 640;
+    //marmalade settings could be changed from emulator's menu
+#endif
+
+
+    example_preinit();
+    core::init(&desc);
+
+
+    //create Stage. Stage is a root node
+    Stage::instance = new Stage(true);
+    Point size = core::getDisplaySize();
+    getStage()->setSize(size);
+
+    //DebugActor is a helper actor node. It shows FPS, memory usage and other useful stuff
+    DebugActor::show();
+
+    //initialize this example stuff. see example.cpp
+    example_init();
+
+#ifdef EMSCRIPTEN
+    /*
+    if you build for Emscripten mainloop would be called automatically outside.
+    see emscripten_set_main_loop below
+    */
+    return;
+#endif
+
+
+    //here is main game loop
+    while (1)
+    {
+        int done = mainloop();
+        if (done)
+            break;
+    }
+    //user wants to leave application...
+
+    //lets dump all created objects into log
+    //all created and not freed resources would be displayed
+    ObjectBase::dumpCreatedObjects();
+
+    //lets cleanup everything right now and call ObjectBase::dumpObjects() again
+    //we need to free all allocated resources and delete all created actors
+    //all actors/sprites are smart pointer objects and actually you don't need it remove them by hands
+    //but now we want delete it by hands
+
+    //check example.cpp
+    example_destroy();
+
+
+    //renderer.cleanup();
+
+    /**releases all internal components and Stage*/
+    core::release();
+
+    //dump list should be empty now
+    //we deleted everything and could be sure that there aren't any memory leaks
+    ObjectBase::dumpCreatedObjects();
+
+    ObjectBase::__stopTracingLeaks();
+    //end
+}
+
+#ifdef __S3E__
+int main(int argc, char* argv[])
+{
+    run();
+    return 0;
+}
+#endif
+
+
+#ifdef OXYGINE_SDL
+
+#include "SDL_main.h"
+extern "C"
+{
+    int main(int argc, char* argv[])
+    {
+        run();
+        return 0;
+    }
+};
+#endif
+
+#ifdef EMSCRIPTEN
+#include <emscripten.h>
+
+void one() { mainloop(); }
+
+int main(int argc, char* argv[])
+{
+    run();
+    emscripten_set_main_loop(one, 0, 0);
+    return 0;
+}
+#endif

+ 57 - 0
example/HelloWorldBilling/src/example.cpp

@@ -0,0 +1,57 @@
+#include "oxygine-framework.h"
+#include <functional>
+#include "test.h"
+#include "billing.h"
+
+
+using namespace oxygine;
+
+
+class TestActor : public Test
+{
+public:
+
+	TestActor()
+	{
+		addButton("purchase", "Purchase");
+	
+	}
+
+
+	void clicked(string id)
+	{
+		billing::purchase("test", "123");
+	}
+};
+
+
+void example_preinit() {}
+
+
+//called from entry_point.cpp
+void example_init()
+{
+	billing::init();
+	billing::dispatcher()->addEventListener(billing::PurchasedEvent::EVENT, [](Event*){
+		Test::instance->notify("purchased");
+	});
+
+	billing::dispatcher()->addEventListener(billing::DetailsEvent::EVENT, [](Event*){
+		Test::instance->notify("details");
+	});
+
+	Test::init();
+	Test::run(new TestActor);
+}
+
+
+//called each frame from entry_point.cpp
+void example_update()
+{
+}
+
+//called each frame from entry_point.cpp
+void example_destroy()
+{
+	Test::free();
+}

+ 4 - 0
example/HelloWorldBilling/src/example.h

@@ -0,0 +1,4 @@
+void example_preinit();
+void example_init();
+void example_destroy();
+void example_update();

+ 240 - 0
example/HelloWorldBilling/src/test.cpp

@@ -0,0 +1,240 @@
+#include "test.h"
+#include "oxygine-framework.h"
+#include "core/STDFileSystem.h"
+
+Resources Test::resourcesUI;
+file::STDFileSystem extfs(true);
+spTest Test::instance;
+
+void Test::init()
+{
+    //mount additional file system with inner path "ext"
+    //it would be used for searching path in data/ext
+    extfs.setPath(file::fs().getFullPath("ext").c_str());
+    file::mount(&extfs);
+
+    resourcesUI.loadXML("demo/res_ui.xml");
+    resourcesUI.loadXML("demo/fonts.xml");
+
+
+    spSprite sp = new Sprite;
+    sp->setResAnim(resourcesUI.getResAnim("logo2"));
+    sp->setInputEnabled(false);
+    sp->attachTo(getStage());
+    sp->setPriority(10);
+    sp->setAlpha(128);
+
+    sp->setX(getStage()->getWidth() - sp->getWidth());
+    sp->setY(getStage()->getHeight() - sp->getHeight());
+}
+
+void Test::run(spTest actor)
+{
+	instance = actor;
+	actor->attachTo(getStage());
+}
+
+void Test::free()
+{
+    resourcesUI.free();
+    instance->detach();
+    instance = 0;
+}
+
+class Toggle: public Button
+{
+public:
+    Toggle(const Test::toggle* t, int num): _current(0)
+    {
+        _items.assign(t, t + num);
+    }
+
+    int _current;
+
+    std::vector<Test::toggle> _items;
+};
+
+spTextField createText(std::string txt)
+{
+    spTextField text = new TextField();
+
+    TextStyle style;
+    style.font = Test::resourcesUI.getResFont("main")->getFont();
+    style.color = Color(72, 61, 139, 255);
+    style.vAlign = TextStyle::VALIGN_MIDDLE;
+    style.hAlign = TextStyle::HALIGN_CENTER;
+    style.multiline = true;
+
+    text->setStyle(style);
+    text->setText(txt.c_str());
+
+    return text;
+}
+
+spButton createButtonHelper(spButton button, string txt, EventCallback cb)
+{
+    button->setPriority(10);
+    //button->setName(id);
+    button->setResAnim(Test::resourcesUI.getResAnim("button"));
+    button->addEventListener(TouchEvent::CLICK, cb);
+
+    //create Actor with Text and it to button as child
+    spTextField text = createText(txt);
+    text->setSize(button->getSize());
+    text->attachTo(button);
+
+    return button;
+}
+
+
+Test::Test()
+{
+    setSize(getStage()->getSize());
+
+    _x = getWidth() - 100;
+    _y = 2;
+
+    ui = new Actor;
+    content = new Content;
+    content->setSize(getSize());
+
+    addChild(content);
+    addChild(ui);
+
+    if (instance)
+    {
+        spButton button = createButtonHelper(new Button, "back", CLOSURE(this, &Test::back));
+        button->setY(getHeight() - button->getHeight());
+        ui->addChild(button);
+    }
+
+    memset(_notifies, 0, sizeof(_notifies));
+}
+
+
+Test::~Test()
+{
+}
+
+
+spButton Test::addButton(std::string id, std::string txt)
+{
+    spButton button = createButtonHelper(new Button, txt, CLOSURE(this, &Test::_clicked));
+    initActor(button.get(),
+              arg_name = id,
+              arg_attachTo = ui,
+              arg_anchor = Vector2(0.5f, 0.0f),
+              arg_pos = Vector2(_x, _y));
+
+    _y += button->getHeight() + 2.0f;
+
+    if (_y + button->getHeight() >= getHeight())
+    {
+        _y = 0;
+        _x += button->getWidth() + 70;
+    }
+
+    return button;
+}
+
+void Test::addToggle(std::string id, const toggle* t, int num)
+{
+    spButton button = createButtonHelper(new Toggle(t, num), t[0].text, CLOSURE(this, &Test::_toggleClicked));
+    initActor(button.get(),
+              arg_name = id,
+              arg_attachTo = ui,
+              arg_anchor = Vector2(0.5f, 0.0f),
+              arg_pos = Vector2(_x, _y));
+
+    _y += button->getHeight() + 2.0f;
+
+    if (_y + button->getHeight() >= getHeight())
+    {
+        _y = 0;
+        _x += button->getWidth() + 70;
+    }
+}
+
+void Test::updateText(std::string id, std::string txt)
+{
+    spActor child = ui->getChild(id);
+    if (!child)
+        return;
+
+    spTextField t = safeSpCast<TextField>(child->getFirstChild());
+    if (!t)
+        return;
+    t->setText(txt);
+}
+
+
+void Test::_clicked(Event* event)
+{
+    clicked(event->currentTarget->getName());
+}
+
+void Test::_toggleClicked(Event* event)
+{
+    Toggle* t = safeCast<Toggle*>(event->currentTarget.get());
+
+    toggleClicked(event->currentTarget->getName(), &t->_items[t->_current]);
+
+    t->_current = (t->_current + 1) % t->_items.size();
+    spTextField ta = safeSpCast<TextField>(t->getFirstChild());
+    const toggle* data = &t->_items[t->_current];
+    ta->setText(data->text);
+}
+
+
+void Test::back(Event* event)
+{
+    detach();
+    instance->setVisible(true);
+}
+
+
+void Test::notify(std::string txt, int time)
+{
+    size_t N = 0;
+    for (size_t i = 0; i < MAX_NOTIFIES; ++i)
+    {
+        if (_notifies[i])
+            continue;
+        N = i;
+        break;
+    }
+
+    _notifies[N] += 1;
+
+
+    spColorRectSprite sprite = new ColorRectSprite();
+    sprite->setUserData((void*)N);
+    sprite->setPriority(10);
+    Color colors[] = {Color(0xD2691EFF), Color(0x7FFFD4FF), Color(0xDC143CFF), Color(0xADFF2FFF), };
+    Color c = colors[rand() % 4];
+    sprite->setColor(c);
+    sprite->setSize(100, 30);
+    //sprite->setAnimFrame(resourcesUI.getResAnim("button"));
+    sprite->setAlpha(0);
+
+    spTweenQueue tq = new TweenQueue;
+    tq->add(Actor::TweenAlpha(255), 300, 1, false, 0, Tween::ease_inExpo);
+    tq->add(Actor::TweenAlpha(0), 300, 1, false, 1200);
+    tq->setDetachActor(true);
+    tq->addDoneCallback(CLOSURE(this, &Test::notifyDone));
+
+    sprite->addTween(tq);
+    sprite->attachTo(ui);
+    sprite->setPosition(2.0f, getHeight() - 100.0f - N * sprite->getHeight() * 1.1f);
+
+    spTextField text = createText(txt);
+    text->attachTo(sprite);
+    text->setColor(Color::Black);
+    text->setPosition(sprite->getSize() / 2);
+}
+
+void Test::notifyDone(Event* ev)
+{
+    size_t N = size_t(ev->target->getUserData());
+    _notifies[N] -= 1;
+}

+ 77 - 0
example/HelloWorldBilling/src/test.h

@@ -0,0 +1,77 @@
+#pragma once
+#include "Actor.h"
+#include "Button.h"
+#include "RenderState.h"
+#include "STDRenderer.h"
+using namespace oxygine;
+using namespace std;
+
+
+spButton createButtonHelper(spButton, std::string txt, EventCallback cb);
+
+class Content: public Actor
+{
+public:
+    Content(): driver(0) {}
+    IVideoDriver* driver;
+
+    void render(const RenderState& parentRS)
+    {
+
+        parentRS.renderer->drawBatch();
+
+        RenderState rs = parentRS;
+        STDRenderer renderer(driver ? driver : IVideoDriver::instance);
+        renderer.begin(parentRS.renderer);
+        rs.renderer = &renderer;
+        Actor::render(rs);
+        renderer.end();
+    }
+};
+
+DECLARE_SMART(Test, spTest);
+class Test: public Actor
+{
+public:
+    Test();
+    ~Test();
+
+    static void init();
+	static void run(spTest actor);
+    static void free();
+    static spTest instance;
+
+    struct toggle
+    {
+        string text;
+        int value;
+        const void* data;
+        toggle() {}
+        toggle(const char* text_, int v_ = 0, const void* data_ = 0): text(text_), value(v_), data(data_) {}
+
+    };
+
+    spButton addButton(string id, string txt);
+    void addToggle(string id, const toggle* t, int num);
+    void updateText(string id, string txt);
+    virtual void clicked(string id) {}
+    virtual void toggleClicked(string id, const toggle* data) {}
+    void _clicked(Event* event);
+    void _toggleClicked(Event* event);
+    void back(Event* event);
+
+    void notify(string text, int time = 400);
+
+protected:
+    void notifyDone(Event* ev);
+
+    float _x;
+    float _y;
+    spActor ui;
+    Content* content;
+    enum {MAX_NOTIFIES = 8};
+    int _notifies[MAX_NOTIFIES];
+
+public:
+    static Resources resourcesUI;
+};

+ 256 - 0
src/android/AndroidBilling.cpp

@@ -0,0 +1,256 @@
+#include <jni.h>
+#include <android/log.h>
+#include <assert.h>
+#include "core/oxygine.h"
+#include "core/Object.h"
+#include "core/ThreadMessages.h"
+#include "core/oxygine.h"
+#include "AndroidBilling.h"
+#include "core/android/jniHelper.h"
+#include "core/android/jniUtils.h"
+#include "billing.h"
+
+#include "json/json.h"
+
+using namespace oxygine;
+
+void billingDetails(JNIEnv* env, jclass cl, jobjectArray array);
+void billingPurchases(JNIEnv* env, jclass cl, jobjectArray array);
+
+
+jclass _jBillingClass = 0;
+jobject _jBillingObject = 0;
+
+bool isBillinEnabled()
+{
+    return _jBillingClass && _jBillingObject;
+}
+
+extern "C"
+{
+    JNIEnv* Android_JNI_GetEnv(void);
+
+    JNIEXPORT void JNICALL Java_org_oxygine_billing_Billing_nativeBillingDetails(JNIEnv* env, jclass cl, jobjectArray jItems)
+    {
+        vector<string> items;
+        jniGetStringArray(items, env, jItems);
+
+        Json::Value vls(Json::arrayValue);
+
+        Json::Reader reader;
+
+
+        for (const auto& item : items)
+        {
+            Json::Value v;
+            reader.parse(item, v, false);
+            vls.append(v);
+        }
+
+        core::getMainThreadMessages().postCallback([ = ]()
+        {
+            billing::internal::detailed(vls);
+        });
+    }
+
+    JNIEXPORT void JNICALL Java_org_oxygine_billing_Billing_nativeBillingPurchases(JNIEnv* env, jclass cl, jobjectArray jItems, jobjectArray jSignatures)
+    {
+        vector<string> items;
+        jniGetStringArray(items, env, jItems);
+
+        vector<string> signatures;
+        jniGetStringArray(signatures, env, jSignatures);
+
+        OX_ASSERT(signatures.size() == items.size());
+
+        core::getMainThreadMessages().postCallback([ = ]()
+        {
+            for (size_t i = 0; i < items.size(); ++i)
+                billing::internal::purchased(items[i], signatures[i]);
+        });
+    }
+
+}
+
+void jniBillingInit()
+{
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        _jBillingClass = (jclass) env->NewGlobalRef(env->FindClass("org/oxygine/billing/Billing"));
+        JNI_NOT_NULL(_jBillingClass);
+
+        _jBillingObject = env->NewGlobalRef(jniFindExtension(env, _jBillingClass));
+        JNI_NOT_NULL(_jBillingObject);
+    }
+    catch (const notFound&)
+    {
+
+    }
+}
+
+void jniBillingFree()
+{
+    if (!isBillinEnabled())
+        return;
+
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        env->DeleteGlobalRef(_jBillingClass);
+        _jBillingClass = 0;
+
+        env->DeleteGlobalRef(_jBillingObject);
+        _jBillingObject = 0;
+    }
+    catch (const notFound&)
+    {
+
+    }
+}
+
+void jniBillingUpdate(const vector<string>& ids)
+{
+    if (!isBillinEnabled())
+        return;
+
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        jclass jclassString = env->FindClass("java/lang/String");
+        JNI_NOT_NULL(jclassString);
+
+
+        jobjectArray array = env->NewObjectArray(ids.size(), jclassString, 0);
+        for (size_t i = 0; i < ids.size(); ++i)
+        {
+            jstring jstr = env->NewStringUTF(ids[i].c_str());
+            env->SetObjectArrayElement(array, i, jstr);
+        }
+
+        jmethodID requestBillingDetails = env->GetMethodID(_jBillingClass, "requestDetails", "([Ljava/lang/String;)V");
+        JNI_NOT_NULL(requestBillingDetails);
+
+        env->CallVoidMethod(_jBillingObject, requestBillingDetails, array);
+
+        __android_log_print(ANDROID_LOG_DEBUG, "SDL", "initBillingDetails end2");
+    }
+    catch (const notFound&)
+    {
+
+    }
+}
+
+void jniBillingConsume(const string& token)
+{
+    if (!isBillinEnabled())
+        return;
+
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        jmethodID jbillingConsume = env->GetMethodID(_jBillingClass, "consume", "(Ljava/lang/String;)V");
+        JNI_NOT_NULL(jbillingConsume);
+
+        jstring jstr = env->NewStringUTF(token.c_str());
+
+        env->CallVoidMethod(_jBillingObject, jbillingConsume, jstr);
+
+    }
+    catch (const notFound&)
+    {
+
+    }
+}
+
+
+string jniBillingGetCurrency()
+{
+    if (!isBillinEnabled())
+        return "";
+
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        jmethodID jbillingGetCurrency = env->GetMethodID(_jBillingClass, "getCurrency", "()Ljava/lang/String;");
+        JNI_NOT_NULL(jbillingGetCurrency);
+
+        jobject obj = env->CallObjectMethod(_jBillingObject, jbillingGetCurrency);
+        jstring my_java_string = (jstring)obj;
+
+        const char* my_c_string = env->GetStringUTFChars(my_java_string, NULL);
+        string cs = "";
+        if (my_c_string != NULL)
+        {
+            cs = my_c_string;
+        }
+        env->ReleaseStringUTFChars(my_java_string, my_c_string);
+
+        return cs;
+
+    }
+    catch (const notFound&)
+    {
+
+    }
+
+    return "";
+}
+
+void _jniGetPurchases(JNIEnv* env)
+{
+    if (!_jBillingClass)
+        return;
+
+    try
+    {
+        LOCAL_REF_HOLDER(env);
+
+        jmethodID jgetPurchases = env->GetMethodID(_jBillingClass, "getPurchases", "()V");
+        JNI_NOT_NULL(jgetPurchases);
+
+        env->CallVoidMethod(_jBillingObject, jgetPurchases);
+    }
+    catch (const notFound&)
+    {
+
+    }
+}
+
+void jniBillingGetPurchases()
+{
+    JNIEnv* env = jniGetEnv();
+    _jniGetPurchases(env);
+}
+
+void jniBillingPurchase(const string& sku, const string& payload)
+{
+    try
+    {
+        JNIEnv* env = jniGetEnv();
+        LOCAL_REF_HOLDER(env);
+
+        jmethodID jpurchase = env->GetMethodID(_jBillingClass, "purchase", "(Ljava/lang/String;Ljava/lang/String;)V");
+        JNI_NOT_NULL(jpurchase);
+
+        jstring jsku = env->NewStringUTF(sku.c_str());
+        jstring jpayload = env->NewStringUTF(payload.c_str());
+
+        env->CallVoidMethod(_jBillingObject, jpurchase, jsku, jpayload);
+
+    }
+    catch (const notFound&)
+    {
+
+    }
+}

+ 12 - 0
src/android/AndroidBilling.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <vector>
+#include <string>
+using namespace std;
+
+void jniBillingInit();
+void jniBillingFree();
+void jniBillingUpdate(const vector<string>& ids);
+void jniBillingPurchase(const string& sku, const string& payload);
+void jniBillingGetPurchases();
+void jniBillingConsume(const string& token);
+string jniBillingGetCurrency();

+ 155 - 0
src/billing.cpp

@@ -0,0 +1,155 @@
+#include "billing.h"
+
+#ifdef __ANDROID__
+#include "android/AndroidBilling.h"
+#else
+#include "sim/BillingSimulator.h"
+#endif
+
+namespace oxygine
+{
+    namespace billing
+    {
+        spEventDispatcher _dispatcher;
+        spEventDispatcher dispatcher()
+        {
+            return _dispatcher;
+        }
+
+        void init()
+        {
+            log::messageln("billing::init");
+            _dispatcher = new EventDispatcher;
+
+#ifdef __ANDROID__
+            jniBillingInit();
+#else
+            billingSimulatorInit();
+#endif
+        }
+
+        void free()
+        {
+            log::messageln("billing::free");
+
+#ifdef __ANDROID__
+            jniBillingFree();
+#endif
+            _dispatcher = 0;
+        }
+
+        void purchase(const std::string& id, const std::string& payload)
+        {
+            log::messageln("billing::purchase %s", id.c_str());
+
+#ifdef __ANDROID__
+            jniBillingPurchase(id, payload);
+#else
+            billingSimulatorPurchase(id, payload);
+#endif
+        }
+
+        void consume(const std::string& token)
+        {
+            log::messageln("billing::consume");
+
+#ifdef __ANDROID__
+            jniBillingConsume(token);
+#else
+            billingSimulatorConsume(token);
+#endif
+        }
+
+        void requestPurchases()
+        {
+            log::messageln("billing::requestPurchases");
+
+#ifdef __ANDROID__
+            jniBillingGetPurchases();
+#else
+            billingSimulatorGetPurchases();
+#endif
+        }
+
+        void requestDetails(const std::vector<std::string>& items)
+        {
+            log::messageln("billing::requestDetails");
+
+#ifdef __ANDROID__
+            jniBillingUpdate(items);
+#else
+            billingSimulatorRequestDetails(items);
+#endif
+        }
+
+        void simulatorSetDetails(const Json::Value& details)
+        {
+#ifdef __ANDROID__
+
+#else
+            billingSimulatorSetDetails(details);
+#endif
+        }
+
+        ParsedDetailsData::ParsedDetailsData(const DetailsEvent* event)
+        {
+            for (Json::ArrayIndex i = 0; i < event->data.size(); ++i)
+            {
+                const Json::Value& item = event->data[i];
+
+                Item it;
+
+#if 1//def __ANDROID__
+                it.productId            = item["productId"].asCString();
+                it.description          = item["description"].asCString();
+                it.price                = item["price"].asCString();
+                it.price_amount_micros  = item["price_amount_micros"].asInt64();
+                it.price_currency_code  = item["price_currency_code"].asCString();
+                it.title                = item["title"].asCString();
+                it.type                 = item["type"].asCString();
+#else
+
+                it.productId = item["productId"].asCString();
+
+#endif
+                items.push_back(it);
+            }
+        }
+
+        namespace internal
+        {
+            void purchased(const std::string& data_, const std::string& sign_)
+            {
+                Json::Value data;
+                Json::Value sign;
+
+                Json::Reader reader;
+                reader.parse(data_, data, false);
+                reader.parse(sign_, sign, false);
+
+                PurchasedEvent ev(data, sign);
+                _dispatcher->dispatchEvent(&ev);
+            }
+
+            void detailed(const Json::Value& data)
+            {
+                DetailsEvent ev(data);
+                _dispatcher->dispatchEvent(&ev);
+            }
+
+            /*
+
+            void detailed(const std::string& data_)
+            {
+                Json::Value data;
+
+                Json::Reader reader;
+                reader.parse(data_, data, false);
+
+                DetailsEvent ev(data);
+                _dispatcher->dispatchEvent(&ev);
+            }
+            */
+        }
+    }
+}

+ 119 - 0
src/billing.h

@@ -0,0 +1,119 @@
+#pragma once
+#include "EventDispatcher.h"
+#include "Event.h"
+#include "json/json.h"
+#include <string>
+
+namespace oxygine
+{
+    namespace billing
+    {
+        class PurchasedEvent : public Event
+        {
+        public:
+            enum { EVENT = sysEventID('b', 'p', 'r') };
+            PurchasedEvent(const Json::Value& data_, const Json::Value& signature_) : Event(EVENT), data(data_), signature(signature_) {}
+
+            Json::Value data;
+            Json::Value signature;
+        };
+
+        class ParsePurchasedData
+        {
+        public:
+            ParsePurchasedData(const PurchasedEvent* event);
+
+            std::string productID;
+        };
+
+        class DetailsEvent : public Event
+        {
+        public:
+            enum { EVENT = sysEventID('b', 'd', 't') };
+            DetailsEvent(const Json::Value& data_) : Event(EVENT), data(data_) {}
+
+            Json::Value data;
+
+
+            /*
+            //android
+            [
+                {
+                    "description" : "A little pack of coins.",
+                        "price" : "30,00 ?",
+                        "price_amount_micros" : 30000000,
+                        "price_currency_code" : "RUB",
+                        "productId" : "com.package.game.pack1",
+                        "title" : "Coins pack 1",
+                        "type" : "inapp"
+                },
+                {
+                    "description" : "A middle pack of coins.",
+                    "price" : "60,00 ?",
+                    "price_amount_micros" : 60000000,
+                    "price_currency_code" : "RUB",
+                    "productId" : "com.package.game.pack2",
+                    "title" : "Coins pack 2",
+                    "type" : "inapp"
+                },
+            ]
+            */
+        };
+
+        class ParsedDetailsData
+        {
+        public:
+            ParsedDetailsData(const DetailsEvent* event);
+
+            class Item
+            {
+            public:
+                Item() : price_amount_micros(0) {}
+
+                std::string     productId;
+                std::string     description;
+                std::string     price;
+                int64           price_amount_micros;
+                std::string     price_currency_code;
+                std::string     title;
+                std::string     type;
+            };
+
+            std::vector<Item> items;
+        };
+
+        spEventDispatcher dispatcher();
+
+        /**initializes oxygine-billing module*/
+        void init();
+
+        /**free oxygine-billing module*/
+        void free();
+
+
+        void purchase(const std::string& id, const std::string& payload);
+        void consume(const std::string& token);
+
+        void requestPurchases();
+        void requestDetails(const std::vector<std::string>& items);
+
+        void simulatorSetDetails(const Json::Value& details);
+
+        enum MarketType
+        {
+            ios,
+            google,
+            amazon
+        };
+
+        MarketType getMarketType();
+
+
+        namespace internal
+        {
+            void purchased(const std::string&, const std::string&);
+            //void detailed(const std::string&);
+            void detailed(const Json::Value&);
+        }
+    }
+}

+ 266 - 0
src/sim/BillingSimulator.cpp

@@ -0,0 +1,266 @@
+#include "BillingSimulator.h"
+#include "Actor.h"
+#include "ColorRectSprite.h"
+#include "TextActor.h"
+#include "Stage.h"
+#include "Box9Sprite.h"
+#include "DebugActor.h"
+#include "res/Resources.h"
+#include "utils/stringUtils.h"
+#include "billing.h"
+#include "core/file.h"
+#include "core/oxygine.h"
+
+using namespace oxygine;
+
+DECLARE_SMART(Btn, spBtn);
+class Btn : public Box9Sprite
+{
+public:
+    Btn()
+    {
+        _txt = new TextActor;
+        _txt->setText("OK");
+        _txt->setAlign(TextStyle::VALIGN_MIDDLE, TextStyle::HALIGN_CENTER);
+        addChild(_txt);
+
+        setColor(Color::Green);
+        setResAnim(DebugActor::resSystem->getResAnim("btn"));
+
+        addEventListener(TouchEvent::OVER, CLOSURE(this, &Btn::touch));
+        addEventListener(TouchEvent::OUT, CLOSURE(this, &Btn::touch));
+    }
+
+    void setText(const string& txt)
+    {
+        _txt->setText(txt);
+    }
+
+    void touch(Event* ev)
+    {
+        if (ev->type == TouchEvent::OVER)
+            setColor(Color::GreenYellow);
+        if (ev->type == TouchEvent::OUT)
+            setColor(Color::Green);
+    }
+
+    void sizeChanged(const Vector2& size)
+    {
+        _txt->setSize(size);
+    }
+
+    spTextActor _txt;
+};
+
+DECLARE_SMART(BillingDialog, spBillingDialog);
+class BillingDialog : public Actor
+{
+public:
+    enum
+    {
+        EVENT_OK = 12323,
+        EVENT_CANCEL
+    };
+
+    BillingDialog()
+    {
+        setPriority(9999);
+
+        spActor blocker = new Actor;
+        blocker->setPosition(-getStage()->getSize());
+        blocker->setSize(getStage()->getSize() * 3);
+        addChild(blocker);
+
+        _bg = new Box9Sprite;
+        addChild(_bg);
+
+        _title = new TextActor;
+        _title->setAlign(TextStyle::VALIGN_MIDDLE, TextStyle::HALIGN_CENTER);
+        _title->setMultiline(true);
+        _title->setColor(Color::Black);
+        addChild(_title);
+
+        _btnOk = new Btn();
+        _btnOk->setSize(70, 30);
+        _btnOk->setText("Ok");
+        addChild(_btnOk);
+
+        _btnCancel = new Btn();
+        _btnCancel->setSize(70, 30);
+        _btnCancel->setText("Cancel");
+        addChild(_btnCancel);
+    }
+
+    void setTitle(const string& txt)
+    {
+        _title->setText(txt);
+    }
+
+    void doRender(const RenderState& rs)
+    {
+        //Stage::render()
+    }
+
+    void sizeChanged(const Vector2& size)
+    {
+        _bg->setSize(size);
+
+        Vector2 center = core::getDisplaySize().cast<Vector2>() / 2.0f;
+        center = getStage()->global2local(center);
+
+        float sx = getStage()->getScaleX();
+        setPosition(center - size / sx / 2);
+
+        _btnOk->setPosition(size - _btnOk->getSize() - Vector2(10, 10));
+        _btnCancel->setPosition(10, getHeight() - 10 - _btnCancel->getHeight());
+        _title->setWidth(getWidth());
+        _title->setHeight(_btnCancel->getY());
+    }
+
+    spBox9Sprite        _bg;
+    spTextActor         _title;
+    spBtn               _btnOk;
+    spBtn               _btnCancel;
+};
+
+
+Json::Value _purchases(Json::arrayValue);
+Json::Value _details(Json::arrayValue);
+
+void billingSimulatorInit()
+{
+    file::buffer bf;
+    file::read(".billing", bf, ep_ignore_error);
+
+    if (!bf.empty())
+    {
+        Json::Reader reader;
+        reader.parse((char*)&bf.front(), (char*)&bf.front() + bf.size(), _purchases, false);
+    }
+}
+
+void save()
+{
+    Json::FastWriter writer;
+    string s = writer.write(_purchases);
+    file::write(".billing", s.c_str(), s.size());
+}
+
+void billingSimulatorPurchase(const string& id, const string& payload)
+{
+    spBillingDialog d = new BillingDialog;
+    d->setScale(1.0f / getStage()->getScaleX());
+    d->setSize(200, 130);
+    getStage()->addChild(d);
+
+    bool alreadyPurchased = false;
+    for (Json::ArrayIndex i = 0; i < _purchases.size(); ++i)
+    {
+        const Json::Value& item = _purchases[i];
+        if (item["data"]["productId"] == id)
+        {
+            alreadyPurchased = true;
+            break;
+        }
+    }
+
+    char str[255];
+    if (alreadyPurchased)
+        safe_sprintf(str, "Item '%s' was already purchased", id.c_str());
+    else
+        safe_sprintf(str, "Purchase Item '%s'?", id.c_str());
+    d->setTitle(str);
+
+
+    if (alreadyPurchased)
+    {
+        d->_btnCancel->setVisible(false);
+        d->_btnOk->addEventListener(TouchEvent::CLICK, [ = ](Event*)
+        {
+            d->detach();
+        });
+    }
+    else
+    {
+        d->_btnOk->addEventListener(TouchEvent::CLICK, [ = ](Event*)
+        {
+            d->detach();
+            getStage()->addTween(TweenDummy(), rand() % 1000 + 500)->setDoneCallback([ = ](Event*)
+            {
+
+                Json::Value data(Json::objectValue);
+                data["productId"] = id;
+                data["purchaseState"] = 0;
+                char str[255];
+                safe_sprintf(str, "%lld", getTimeUTCMS());
+                data["purchaseToken"] = str;
+
+                Json::Value item(Json::objectValue);
+                item["data"] = data;
+                item["sign"] = "qwe";
+
+                _purchases.append(item);
+                save();
+
+                Json::FastWriter writer;
+                billing::internal::purchased(writer.write(data), item["sign"].asCString());
+            });
+        });
+
+        d->_btnCancel->addEventListener(TouchEvent::CLICK, [ = ](Event*)
+        {
+            d->detach();
+        });
+    }
+}
+
+void billingSimulatorConsume(const string& token)
+{
+    for (Json::ArrayIndex i = 0; i < _purchases.size(); ++i)
+    {
+        string s = _purchases[i]["data"]["purchaseToken"].asString();
+        if (s == token)
+        {
+            Json::Value v;
+            _purchases.removeIndex(i, &v);
+            break;
+        }
+    }
+
+    save();
+}
+
+void billingSimulatorGetPurchases()
+{
+    getStage()->addTween(TweenDummy(), rand() % 1000 + 500)->setDoneCallback([ = ](Event*)
+    {
+        Json::Value copy = _purchases;
+        for (Json::ArrayIndex i = 0; i < copy.size(); ++i)
+        {
+            const Json::Value& item = copy[i];
+
+            Json::FastWriter writer;
+            billing::internal::purchased(writer.write(item["data"]), item["sign"].asCString());
+        }
+    });
+}
+
+void billingSimulatorRequestDetails(const vector<string>& items)
+{
+    getStage()->addTween(TweenDummy(), rand() % 1000 + 500)->setDoneCallback([ = ](Event*)
+    {
+        billing::internal::detailed(_details);
+    });
+}
+
+void billingSimulatorSetDetails(const Json::Value& details)
+{
+    _details.clear();
+
+    for (Json::ArrayIndex i = 0; i < details.size(); ++i)
+    {
+        const Json::Value& item = details[i];
+
+        _details.append(item);
+    }
+}

+ 12 - 0
src/sim/BillingSimulator.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <string>
+#include <vector>
+#include "json/json.h"
+using namespace std;
+
+void billingSimulatorInit();
+void billingSimulatorPurchase(const string& id, const string& payload);
+void billingSimulatorConsume(const string& token);
+void billingSimulatorGetPurchases();
+void billingSimulatorRequestDetails(const vector<string>& items);
+void billingSimulatorSetDetails(const Json::Value& details);