<commit_before>#ifdef PLATFORM_ANDROID

#include "platform_android.h"
#include "data/properties.h"
#include "data/propertyItem.h"
#include "tangram.h"

#include <GLES2/gl2platform.h>

#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES 1
#endif

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <dlfcn.h> // dlopen, dlsym

#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <cstdarg>

#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <fstream>
#include <algorithm>

#include <regex>

/* Followed the following document for JavaVM tips when used with native threads
 * http://android.wooyd.org/JNIExample/#NWD1sCYeT-I
 * http://developer.android.com/training/articles/perf-jni.html and
 * http://www.ibm.com/developerworks/library/j-jni/
 * http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html
 */

static JavaVM* jvm = nullptr;
// JNI Env bound on androids render thread (our native main thread)
static JNIEnv* jniRenderThreadEnv = nullptr;
static jobject tangramInstance = nullptr;
static jmethodID requestRenderMethodID = 0;
static jmethodID setRenderModeMethodID = 0;
static jmethodID startUrlRequestMID = 0;
static jmethodID cancelUrlRequestMID = 0;
static jmethodID getFontFilePath = 0;
static jmethodID getFontFallbackFilePath = 0;
static jmethodID onFeaturePickMID = 0;

static jclass hashmapClass = nullptr;
static jmethodID hashmapInitMID = 0;
static jmethodID hashmapPutMID = 0;

static AAssetManager* assetManager = nullptr;

static bool s_isContinuousRendering = false;

PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT = 0;
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT = 0;
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT = 0;

void bindJniEnvToThread(JNIEnv* jniEnv) {
    jniEnv->GetJavaVM(&jvm);
    jniRenderThreadEnv = jniEnv;
}

void setupJniEnv(JNIEnv* jniEnv, jobject _tangramInstance, jobject _assetManager) {
    bindJniEnvToThread(jniEnv);
    if (tangramInstance) {
        jniEnv->DeleteGlobalRef(tangramInstance);
    }
    tangramInstance = jniEnv->NewGlobalRef(_tangramInstance);
    jclass tangramClass = jniEnv->FindClass("com/mapzen/tangram/MapController");
    startUrlRequestMID = jniEnv->GetMethodID(tangramClass, "startUrlRequest", "(Ljava/lang/String;J)Z");
    cancelUrlRequestMID = jniEnv->GetMethodID(tangramClass, "cancelUrlRequest", "(Ljava/lang/String;)V");
    getFontFilePath = jniEnv->GetMethodID(tangramClass, "getFontFilePath", "(Ljava/lang/String;)Ljava/lang/String;");
    getFontFallbackFilePath = jniEnv->GetMethodID(tangramClass, "getFontFallbackFilePath", "(II)Ljava/lang/String;");
    requestRenderMethodID = jniEnv->GetMethodID(tangramClass, "requestRender", "()V");
    setRenderModeMethodID = jniEnv->GetMethodID(tangramClass, "setRenderMode", "(I)V");

    jclass featurePickListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$FeaturePickListener");
    onFeaturePickMID = jniEnv->GetMethodID(featurePickListenerClass, "onFeaturePick", "(Ljava/util/Map;FF)V");

    if (hashmapClass) {
        jniEnv->DeleteGlobalRef(hashmapClass);
    }
    hashmapClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("java/util/HashMap"));
    hashmapInitMID = jniEnv->GetMethodID(hashmapClass, "<init>", "()V");
    hashmapPutMID = jniEnv->GetMethodID(hashmapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

    assetManager = AAssetManager_fromJava(jniEnv, _assetManager);

    if (assetManager == nullptr) {
        logMsg("ERROR: Could not obtain Asset Manager reference\n");
    }

}

void logMsg(const char* fmt, ...) {

    va_list args;
    va_start(args, fmt);
    __android_log_vprint(ANDROID_LOG_DEBUG, "Tangram", fmt, args);
    va_end(args);

}

class JniThreadBinding {
private:
    JavaVM* jvm;
    JNIEnv *jniEnv;
    int status;
public:
    JniThreadBinding(JavaVM* _jvm) : jvm(_jvm) {
        status = jvm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6);
        if (status == JNI_EDETACHED) { jvm->AttachCurrentThread(&jniEnv, NULL);}
    }
    ~JniThreadBinding() {
        if (status == JNI_EDETACHED) { jvm->DetachCurrentThread(); }
    }

    JNIEnv* operator->() const {
        return jniEnv;
    }

    operator JNIEnv*() const {
        return jniEnv;
    }
};

void requestRender() {

    JniThreadBinding jniEnv(jvm);

    jniEnv->CallVoidMethod(tangramInstance, requestRenderMethodID);
}

std::string systemFontFallbackPath(int _importance, int _weightHint) {

    JniThreadBinding jniEnv(jvm);

    jstring returnStr = (jstring) jniEnv->CallObjectMethod(tangramInstance, getFontFallbackFilePath, _importance, _weightHint);

    auto resultStr = stringFromJString(jniEnv, returnStr);
    jniEnv->DeleteLocalRef(returnStr);

    return resultStr;
}

std::string systemFontPath(const std::string& _family, const std::string& _weight, const std::string& _style) {

    JniThreadBinding jniEnv(jvm);

    std::string key = _family + "_" + _weight + "_" + _style;

    jstring jkey = jniEnv->NewStringUTF(key.c_str());
    jstring returnStr = (jstring) jniEnv->CallObjectMethod(tangramInstance, getFontFilePath, jkey);

    auto resultStr = stringFromJString(jniEnv, returnStr);
    jniEnv->DeleteLocalRef(returnStr);
    jniEnv->DeleteLocalRef(jkey);

    return resultStr;
}

void setContinuousRendering(bool _isContinuous) {

    s_isContinuousRendering = _isContinuous;

    JniThreadBinding jniEnv(jvm);

    jniEnv->CallVoidMethod(tangramInstance, setRenderModeMethodID, _isContinuous ? 1 : 0);
}

bool isContinuousRendering() {

    return s_isContinuousRendering;

}

unsigned char* bytesFromAssetManager(const char* _path, size_t& _size) {

    unsigned char* data = nullptr;

    AAsset* asset = AAssetManager_open(assetManager, _path, AASSET_MODE_UNKNOWN);

    if (asset == nullptr) {
        logMsg("Failed to open asset at path: %s\n", _path);
        _size = 0;
        return data;
    }

    _size = AAsset_getLength(asset);

    data = (unsigned char*) malloc(sizeof(unsigned char) * _size);

    int read = AAsset_read(asset, data, _size);

    if (read <= 0) {
        logMsg("Failed to read asset at path: %s\n", _path);
    }

    AAsset_close(asset);

    return data;
}

unsigned char* bytesFromFileSystem(const char* _path, size_t& _size) {

    std::ifstream resource(_path, std::ifstream::ate | std::ifstream::binary);

    if(!resource.is_open()) {
        logMsg("Failed to read file at path: %s\n", _path);
        _size = 0;
        return nullptr;
    }

    _size = resource.tellg();

    resource.seekg(std::ifstream::beg);

    char* cdata = (char*) malloc(sizeof(char) * _size);

    resource.read(cdata, _size);
    resource.close();

    return reinterpret_cast<unsigned char *>(cdata);

}

std::string stringFromFile(const char* _path) {

    unsigned int length = 0;
    unsigned char* bytes = bytesFromFile(_path, length);
    std::string out(reinterpret_cast<char*>(bytes), length);
    free(bytes);

    return out;

}

unsigned char* bytesFromFile(const char* _path, size_t& _size) {

    size_t len = strlen(_path);

    if (len > 0) {
        if (_path[0] == '/') {

            return bytesFromFileSystem(_path, _size);

        } else {
            // For unclear reasons, the AAssetManager will fail to open a file at
            // path "filepath" if the path is instead given as "./filepath"
            if (len >= 2 && (_path[0] == '.') && (_path[1] == '/')) { _path += 2; }

            return bytesFromAssetManager(_path, _size);
        }
    }
    _size = 0;
    return nullptr;
}

bool startUrlRequest(const std::string& _url, UrlCallback _callback) {

    jstring jUrl = jniRenderThreadEnv->NewStringUTF(_url.c_str());

    // This is probably super dangerous. In order to pass a reference to our callback we have to convert it
    // to a Java type. We allocate a new callback object and then reinterpret the pointer to it as a Java long.
    // In Java, we associate this long with the current network request and pass it back to native code when
    // the request completes (either in onUrlSuccess or onUrlFailure), reinterpret the long back into a
    // pointer, call the callback function if the request succeeded, and delete the heap-allocated UrlCallback
    // to make sure nothing is leaked.
    jlong jCallbackPtr = reinterpret_cast<jlong>(new UrlCallback(_callback));

    jboolean methodResult = jniRenderThreadEnv->CallBooleanMethod(tangramInstance, startUrlRequestMID, jUrl, jCallbackPtr);

    return methodResult;
}

void cancelUrlRequest(const std::string& _url) {
    jstring jUrl = jniRenderThreadEnv->NewStringUTF(_url.c_str());
    jniRenderThreadEnv->CallVoidMethod(tangramInstance, cancelUrlRequestMID, jUrl);
}

void onUrlSuccess(JNIEnv* _jniEnv, jbyteArray _jBytes, jlong _jCallbackPtr) {

    size_t length = _jniEnv->GetArrayLength(_jBytes);
    std::vector<char> content;
    content.resize(length);

    _jniEnv->GetByteArrayRegion(_jBytes, 0, length, reinterpret_cast<jbyte*>(content.data()));

    UrlCallback* callback = reinterpret_cast<UrlCallback*>(_jCallbackPtr);
    (*callback)(std::move(content));
    delete callback;
}

void onUrlFailure(JNIEnv* _jniEnv, jlong _jCallbackPtr) {
    std::vector<char> empty;

    UrlCallback* callback = reinterpret_cast<UrlCallback*>(_jCallbackPtr);
    (*callback)(std::move(empty));
    delete callback;
}

void setCurrentThreadPriority(int priority) {
    int  tid = gettid();
    setpriority(PRIO_PROCESS, tid, priority);
}

void featurePickCallback(JNIEnv* jniEnv, jobject listener, const std::vector<Tangram::TouchItem>& items) {

    auto result = items[0];
    auto properties = result.properties;
    auto position = result.position;

    jobject hashmap = jniEnv->NewObject(hashmapClass, hashmapInitMID);

    for (const auto& item : properties->items()) {
        jstring jkey = jniEnv->NewStringUTF(item.key.c_str());
        jstring jvalue = jniEnv->NewStringUTF(properties->asString(item.value).c_str());
        jniEnv->CallObjectMethod(hashmap, hashmapPutMID, jkey, jvalue);
    }

    jniEnv->CallVoidMethod(listener, onFeaturePickMID, hashmap, position[0], position[1]);
}

void initGLExtensions() {
    void* libhandle = dlopen("libGLESv2.so", RTLD_LAZY);

    glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYOESPROC) dlsym(libhandle, "glBindVertexArrayOES");
    glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSOESPROC) dlsym(libhandle, "glDeleteVertexArraysOES");
    glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSOESPROC) dlsym(libhandle, "glGenVertexArraysOES");
}

std::string stringFromJString(JNIEnv* jniEnv, jstring string) {
    size_t length = jniEnv->GetStringLength(string);
    std::string out(length, 0);
    jniEnv->GetStringUTFRegion(string, 0, length, &out[0]);
    return out;
}

#endif
<commit_msg>android arm64-v8a arch strictness for size_t<commit_after>#ifdef PLATFORM_ANDROID

#include "platform_android.h"
#include "data/properties.h"
#include "data/propertyItem.h"
#include "tangram.h"

#include <GLES2/gl2platform.h>

#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES 1
#endif

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <dlfcn.h> // dlopen, dlsym

#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <cstdarg>

#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <fstream>
#include <algorithm>

#include <regex>

/* Followed the following document for JavaVM tips when used with native threads
 * http://android.wooyd.org/JNIExample/#NWD1sCYeT-I
 * http://developer.android.com/training/articles/perf-jni.html and
 * http://www.ibm.com/developerworks/library/j-jni/
 * http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html
 */

static JavaVM* jvm = nullptr;
// JNI Env bound on androids render thread (our native main thread)
static JNIEnv* jniRenderThreadEnv = nullptr;
static jobject tangramInstance = nullptr;
static jmethodID requestRenderMethodID = 0;
static jmethodID setRenderModeMethodID = 0;
static jmethodID startUrlRequestMID = 0;
static jmethodID cancelUrlRequestMID = 0;
static jmethodID getFontFilePath = 0;
static jmethodID getFontFallbackFilePath = 0;
static jmethodID onFeaturePickMID = 0;

static jclass hashmapClass = nullptr;
static jmethodID hashmapInitMID = 0;
static jmethodID hashmapPutMID = 0;

static AAssetManager* assetManager = nullptr;

static bool s_isContinuousRendering = false;

PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT = 0;
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT = 0;
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT = 0;

void bindJniEnvToThread(JNIEnv* jniEnv) {
    jniEnv->GetJavaVM(&jvm);
    jniRenderThreadEnv = jniEnv;
}

void setupJniEnv(JNIEnv* jniEnv, jobject _tangramInstance, jobject _assetManager) {
    bindJniEnvToThread(jniEnv);
    if (tangramInstance) {
        jniEnv->DeleteGlobalRef(tangramInstance);
    }
    tangramInstance = jniEnv->NewGlobalRef(_tangramInstance);
    jclass tangramClass = jniEnv->FindClass("com/mapzen/tangram/MapController");
    startUrlRequestMID = jniEnv->GetMethodID(tangramClass, "startUrlRequest", "(Ljava/lang/String;J)Z");
    cancelUrlRequestMID = jniEnv->GetMethodID(tangramClass, "cancelUrlRequest", "(Ljava/lang/String;)V");
    getFontFilePath = jniEnv->GetMethodID(tangramClass, "getFontFilePath", "(Ljava/lang/String;)Ljava/lang/String;");
    getFontFallbackFilePath = jniEnv->GetMethodID(tangramClass, "getFontFallbackFilePath", "(II)Ljava/lang/String;");
    requestRenderMethodID = jniEnv->GetMethodID(tangramClass, "requestRender", "()V");
    setRenderModeMethodID = jniEnv->GetMethodID(tangramClass, "setRenderMode", "(I)V");

    jclass featurePickListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$FeaturePickListener");
    onFeaturePickMID = jniEnv->GetMethodID(featurePickListenerClass, "onFeaturePick", "(Ljava/util/Map;FF)V");

    if (hashmapClass) {
        jniEnv->DeleteGlobalRef(hashmapClass);
    }
    hashmapClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("java/util/HashMap"));
    hashmapInitMID = jniEnv->GetMethodID(hashmapClass, "<init>", "()V");
    hashmapPutMID = jniEnv->GetMethodID(hashmapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

    assetManager = AAssetManager_fromJava(jniEnv, _assetManager);

    if (assetManager == nullptr) {
        logMsg("ERROR: Could not obtain Asset Manager reference\n");
    }

}

void logMsg(const char* fmt, ...) {

    va_list args;
    va_start(args, fmt);
    __android_log_vprint(ANDROID_LOG_DEBUG, "Tangram", fmt, args);
    va_end(args);

}

class JniThreadBinding {
private:
    JavaVM* jvm;
    JNIEnv *jniEnv;
    int status;
public:
    JniThreadBinding(JavaVM* _jvm) : jvm(_jvm) {
        status = jvm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6);
        if (status == JNI_EDETACHED) { jvm->AttachCurrentThread(&jniEnv, NULL);}
    }
    ~JniThreadBinding() {
        if (status == JNI_EDETACHED) { jvm->DetachCurrentThread(); }
    }

    JNIEnv* operator->() const {
        return jniEnv;
    }

    operator JNIEnv*() const {
        return jniEnv;
    }
};

void requestRender() {

    JniThreadBinding jniEnv(jvm);

    jniEnv->CallVoidMethod(tangramInstance, requestRenderMethodID);
}

std::string systemFontFallbackPath(int _importance, int _weightHint) {

    JniThreadBinding jniEnv(jvm);

    jstring returnStr = (jstring) jniEnv->CallObjectMethod(tangramInstance, getFontFallbackFilePath, _importance, _weightHint);

    auto resultStr = stringFromJString(jniEnv, returnStr);
    jniEnv->DeleteLocalRef(returnStr);

    return resultStr;
}

std::string systemFontPath(const std::string& _family, const std::string& _weight, const std::string& _style) {

    JniThreadBinding jniEnv(jvm);

    std::string key = _family + "_" + _weight + "_" + _style;

    jstring jkey = jniEnv->NewStringUTF(key.c_str());
    jstring returnStr = (jstring) jniEnv->CallObjectMethod(tangramInstance, getFontFilePath, jkey);

    auto resultStr = stringFromJString(jniEnv, returnStr);
    jniEnv->DeleteLocalRef(returnStr);
    jniEnv->DeleteLocalRef(jkey);

    return resultStr;
}

void setContinuousRendering(bool _isContinuous) {

    s_isContinuousRendering = _isContinuous;

    JniThreadBinding jniEnv(jvm);

    jniEnv->CallVoidMethod(tangramInstance, setRenderModeMethodID, _isContinuous ? 1 : 0);
}

bool isContinuousRendering() {

    return s_isContinuousRendering;

}

unsigned char* bytesFromAssetManager(const char* _path, size_t& _size) {

    unsigned char* data = nullptr;

    AAsset* asset = AAssetManager_open(assetManager, _path, AASSET_MODE_UNKNOWN);

    if (asset == nullptr) {
        logMsg("Failed to open asset at path: %s\n", _path);
        _size = 0;
        return data;
    }

    _size = AAsset_getLength(asset);

    data = (unsigned char*) malloc(sizeof(unsigned char) * _size);

    int read = AAsset_read(asset, data, _size);

    if (read <= 0) {
        logMsg("Failed to read asset at path: %s\n", _path);
    }

    AAsset_close(asset);

    return data;
}

unsigned char* bytesFromFileSystem(const char* _path, size_t& _size) {

    std::ifstream resource(_path, std::ifstream::ate | std::ifstream::binary);

    if(!resource.is_open()) {
        logMsg("Failed to read file at path: %s\n", _path);
        _size = 0;
        return nullptr;
    }

    _size = resource.tellg();

    resource.seekg(std::ifstream::beg);

    char* cdata = (char*) malloc(sizeof(char) * _size);

    resource.read(cdata, _size);
    resource.close();

    return reinterpret_cast<unsigned char *>(cdata);

}

std::string stringFromFile(const char* _path) {

    size_t length = 0;
    unsigned char* bytes = bytesFromFile(_path, length);
    std::string out(reinterpret_cast<char*>(bytes), length);
    free(bytes);

    return out;

}

unsigned char* bytesFromFile(const char* _path, size_t& _size) {

    size_t len = strlen(_path);

    if (len > 0) {
        if (_path[0] == '/') {

            return bytesFromFileSystem(_path, _size);

        } else {
            // For unclear reasons, the AAssetManager will fail to open a file at
            // path "filepath" if the path is instead given as "./filepath"
            if (len >= 2 && (_path[0] == '.') && (_path[1] == '/')) { _path += 2; }

            return bytesFromAssetManager(_path, _size);
        }
    }
    _size = 0;
    return nullptr;
}

bool startUrlRequest(const std::string& _url, UrlCallback _callback) {

    jstring jUrl = jniRenderThreadEnv->NewStringUTF(_url.c_str());

    // This is probably super dangerous. In order to pass a reference to our callback we have to convert it
    // to a Java type. We allocate a new callback object and then reinterpret the pointer to it as a Java long.
    // In Java, we associate this long with the current network request and pass it back to native code when
    // the request completes (either in onUrlSuccess or onUrlFailure), reinterpret the long back into a
    // pointer, call the callback function if the request succeeded, and delete the heap-allocated UrlCallback
    // to make sure nothing is leaked.
    jlong jCallbackPtr = reinterpret_cast<jlong>(new UrlCallback(_callback));

    jboolean methodResult = jniRenderThreadEnv->CallBooleanMethod(tangramInstance, startUrlRequestMID, jUrl, jCallbackPtr);

    return methodResult;
}

void cancelUrlRequest(const std::string& _url) {
    jstring jUrl = jniRenderThreadEnv->NewStringUTF(_url.c_str());
    jniRenderThreadEnv->CallVoidMethod(tangramInstance, cancelUrlRequestMID, jUrl);
}

void onUrlSuccess(JNIEnv* _jniEnv, jbyteArray _jBytes, jlong _jCallbackPtr) {

    size_t length = _jniEnv->GetArrayLength(_jBytes);
    std::vector<char> content;
    content.resize(length);

    _jniEnv->GetByteArrayRegion(_jBytes, 0, length, reinterpret_cast<jbyte*>(content.data()));

    UrlCallback* callback = reinterpret_cast<UrlCallback*>(_jCallbackPtr);
    (*callback)(std::move(content));
    delete callback;
}

void onUrlFailure(JNIEnv* _jniEnv, jlong _jCallbackPtr) {
    std::vector<char> empty;

    UrlCallback* callback = reinterpret_cast<UrlCallback*>(_jCallbackPtr);
    (*callback)(std::move(empty));
    delete callback;
}

void setCurrentThreadPriority(int priority) {
    int  tid = gettid();
    setpriority(PRIO_PROCESS, tid, priority);
}

void featurePickCallback(JNIEnv* jniEnv, jobject listener, const std::vector<Tangram::TouchItem>& items) {

    auto result = items[0];
    auto properties = result.properties;
    auto position = result.position;

    jobject hashmap = jniEnv->NewObject(hashmapClass, hashmapInitMID);

    for (const auto& item : properties->items()) {
        jstring jkey = jniEnv->NewStringUTF(item.key.c_str());
        jstring jvalue = jniEnv->NewStringUTF(properties->asString(item.value).c_str());
        jniEnv->CallObjectMethod(hashmap, hashmapPutMID, jkey, jvalue);
    }

    jniEnv->CallVoidMethod(listener, onFeaturePickMID, hashmap, position[0], position[1]);
}

void initGLExtensions() {
    void* libhandle = dlopen("libGLESv2.so", RTLD_LAZY);

    glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYOESPROC) dlsym(libhandle, "glBindVertexArrayOES");
    glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSOESPROC) dlsym(libhandle, "glDeleteVertexArraysOES");
    glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSOESPROC) dlsym(libhandle, "glGenVertexArraysOES");
}

std::string stringFromJString(JNIEnv* jniEnv, jstring string) {
    size_t length = jniEnv->GetStringLength(string);
    std::string out(length, 0);
    jniEnv->GetStringUTFRegion(string, 0, length, &out[0]);
    return out;
}

#endif
<|endoftext|>


<commit_before>/* Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.

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. */

#include "paddle/fluid/operators/inverse_op.h"
#include <string>
#include <unordered_map>

namespace paddle {
namespace operators {

class InverseOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    OP_INOUT_CHECK(ctx->HasInput("Input"), "Input", "Input", "Inverse");
    OP_INOUT_CHECK(ctx->HasOutput("Output"), "Output", "Output", "Inverse");

    auto input_dims = ctx->GetInputDim("Input");
    int64_t input_rank = input_dims.size();
    PADDLE_ENFORCE_GE(
        input_rank, 2,
        platform::errors::InvalidArgument(
            "The dimension of Input(Input) is expected to be no less than 2. "
            "But recieved: Input(Input)'s dimension = %d, shape = [%s].",
            input_rank, input_dims));
    if (input_dims[input_rank - 2] > 0 && input_dims[input_rank - 1] > 0) {
      PADDLE_ENFORCE_EQ(input_dims[input_rank - 2], input_dims[input_rank - 1],
                        platform::errors::InvalidArgument(
                            "The last two dimensions are expected to be equal. "
                            "But recieved: %d and %d; "
                            "Input(Input)'s shape = [%s].",
                            input_dims[input_rank - 2],
                            input_dims[input_rank - 1], input_dims));
    }

    ctx->SetOutputDim("Output", input_dims);
    ctx->ShareLoD("Input", /*->*/ "Output");
  }
};

class InverseOpInferVarType : public framework::PassInDtypeAndVarTypeToOutput {
 protected:
  std::unordered_map<std::string, std::string>& GetInputOutputWithSameType()
      const override {
    static std::unordered_map<std::string, std::string> m{
        {"Input", /*->*/ "Output"}};
    return m;
  }
};

class InverseGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    auto input_grad = framework::GradVarName("Input");
    auto output_grad = framework::GradVarName("Output");

    OP_INOUT_CHECK(ctx->HasInput("Output"), "Input", "Output", "InverseGrad");
    OP_INOUT_CHECK(ctx->HasInput(output_grad), "Input", output_grad,
                   "InverseGrad");

    if (ctx->HasOutput(input_grad)) {
      ctx->SetOutputDim(input_grad, ctx->GetInputDim(output_grad));
    }
  }
};

class InverseOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput(
        "Input",
        "(Tensor) A square matrix (2-D Tensor) or batches of square matrices"
        " to inverse.");
    AddOutput("Output", "(Tensor) The inverse of input matrix.");
    AddComment(R"DOC(
Inverse Operator

Takes the inverse of the square matrix.
)DOC");
  }
};

template <typename T>
class InverseGradOpMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  void Apply(GradOpPtr<T> grad) const override {
    grad->SetType(this->ForwardOpType() + "_grad");
    grad->SetInput("Output", this->Output("Output"));
    grad->SetInput(framework::GradVarName("Output"),
                   this->OutputGrad("Output"));
    grad->SetOutput(framework::GradVarName("Input"), this->InputGrad("Input"));
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(inverse, ops::InverseOp, ops::InverseOpMaker,
                  ops::InverseOpInferVarType,
                  ops::InverseGradOpMaker<paddle::framework::OpDesc>,
                  ops::InverseGradOpMaker<paddle::imperative::OpBase>);

REGISTER_OPERATOR(inverse_grad, ops::InverseGradOp);

REGISTER_OP_CPU_KERNEL(
    inverse, ops::InverseKernel<paddle::platform::CPUDeviceContext, float>,
    ops::InverseKernel<paddle::platform::CPUDeviceContext, double>);
REGISTER_OP_CPU_KERNEL(
    inverse_grad,
    ops::InverseGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::InverseGradKernel<paddle::platform::CPUDeviceContext, double>);
<commit_msg>Add dimension check for inverse to avoid dividing by 0 error when input's shape is [0, 0, 0]. (#34996)<commit_after>/* Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.

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. */

#include "paddle/fluid/operators/inverse_op.h"
#include <string>
#include <unordered_map>

namespace paddle {
namespace operators {

class InverseOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    OP_INOUT_CHECK(ctx->HasInput("Input"), "Input", "Input", "Inverse");
    OP_INOUT_CHECK(ctx->HasOutput("Output"), "Output", "Output", "Inverse");

    auto input_dims = ctx->GetInputDim("Input");
    int64_t input_rank = input_dims.size();
    PADDLE_ENFORCE_GE(
        input_rank, 2,
        platform::errors::InvalidArgument(
            "The dimension of Input(Input) is expected to be no less than 2. "
            "But recieved: Input(Input)'s dimension = %d, shape = [%s].",
            input_rank, input_dims));
    for (int64_t i = 0; i < input_rank; ++i) {
      PADDLE_ENFORCE_EQ(
          (input_dims[i] == -1) || (input_dims[i] > 0), true,
          platform::errors::InvalidArgument(
              "Each dimension of input tensor is expected to be -1 or a "
              "positive number, but recieved %d. Input's shape is [%s].",
              input_dims[i], input_dims));
    }
    if (input_dims[input_rank - 2] > 0 && input_dims[input_rank - 1] > 0) {
      PADDLE_ENFORCE_EQ(input_dims[input_rank - 2], input_dims[input_rank - 1],
                        platform::errors::InvalidArgument(
                            "The last two dimensions are expected to be equal. "
                            "But recieved: %d and %d; "
                            "Input(Input)'s shape = [%s].",
                            input_dims[input_rank - 2],
                            input_dims[input_rank - 1], input_dims));
    }

    ctx->SetOutputDim("Output", input_dims);
    ctx->ShareLoD("Input", /*->*/ "Output");
  }
};

class InverseOpInferVarType : public framework::PassInDtypeAndVarTypeToOutput {
 protected:
  std::unordered_map<std::string, std::string>& GetInputOutputWithSameType()
      const override {
    static std::unordered_map<std::string, std::string> m{
        {"Input", /*->*/ "Output"}};
    return m;
  }
};

class InverseGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    auto input_grad = framework::GradVarName("Input");
    auto output_grad = framework::GradVarName("Output");

    OP_INOUT_CHECK(ctx->HasInput("Output"), "Input", "Output", "InverseGrad");
    OP_INOUT_CHECK(ctx->HasInput(output_grad), "Input", output_grad,
                   "InverseGrad");

    if (ctx->HasOutput(input_grad)) {
      ctx->SetOutputDim(input_grad, ctx->GetInputDim(output_grad));
    }
  }
};

class InverseOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput(
        "Input",
        "(Tensor) A square matrix (2-D Tensor) or batches of square matrices"
        " to inverse.");
    AddOutput("Output", "(Tensor) The inverse of input matrix.");
    AddComment(R"DOC(
Inverse Operator

Takes the inverse of the square matrix.
)DOC");
  }
};

template <typename T>
class InverseGradOpMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  void Apply(GradOpPtr<T> grad) const override {
    grad->SetType(this->ForwardOpType() + "_grad");
    grad->SetInput("Output", this->Output("Output"));
    grad->SetInput(framework::GradVarName("Output"),
                   this->OutputGrad("Output"));
    grad->SetOutput(framework::GradVarName("Input"), this->InputGrad("Input"));
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(inverse, ops::InverseOp, ops::InverseOpMaker,
                  ops::InverseOpInferVarType,
                  ops::InverseGradOpMaker<paddle::framework::OpDesc>,
                  ops::InverseGradOpMaker<paddle::imperative::OpBase>);

REGISTER_OPERATOR(inverse_grad, ops::InverseGradOp);

REGISTER_OP_CPU_KERNEL(
    inverse, ops::InverseKernel<paddle::platform::CPUDeviceContext, float>,
    ops::InverseKernel<paddle::platform::CPUDeviceContext, double>);
REGISTER_OP_CPU_KERNEL(
    inverse_grad,
    ops::InverseGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::InverseGradKernel<paddle::platform::CPUDeviceContext, double>);
<|endoftext|>


<commit_before>#include "PhysicsManager.hpp"

#include <btBulletDynamicsCommon.h>
#include <glm/gtx/quaternion.hpp>
#include "../Component/RigidBody.hpp"
#include "../Component/Shape.hpp"
#include "../Entity/Entity.hpp"
#include "../Physics/GlmConversion.hpp"
#include "../Physics/Shape.hpp"
#include "../Physics/Trigger.hpp"
#include "../Physics/TriggerObserver.hpp"
#include "../Util/Json.hpp"

PhysicsManager::PhysicsManager() {
    // The broadphase is used to quickly cull bodies that will not collide with
    // each other, normally by leveraging some simpler (and rough) test such as
    // bounding boxes.
    broadphase = new btDbvtBroadphase;

    // With the collision configuration one can configure collision detection
    // algorithms.
    collisionConfiguration = new btDefaultCollisionConfiguration;
    dispatcher = new btCollisionDispatcher(collisionConfiguration);

    // The solver makes objects interact by making use of gravity, collisions,
    // game logic supplied forces, and constraints.
    solver = new btSequentialImpulseConstraintSolver;

    // The dynamics world encompasses objects included in the simulation.
    dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);

    // Y axis up
    dynamicsWorld->setGravity(btVector3(0, -9.82, 0));

    // Set the lockbox key we will use for lockboxes created in here.
    triggerLockBoxKey.reset(new Utility::LockBox<Physics::Trigger>::Key());
}

PhysicsManager::~PhysicsManager() {
    delete dynamicsWorld;
    delete solver;
    delete dispatcher;
    delete collisionConfiguration;
    delete broadphase;

    for (auto t : triggers)
        delete t;
}

void PhysicsManager::Update(float deltaTime) {
    for (auto rigidBodyComp : rigidBodyComponents.GetAll()) {
        if (rigidBodyComp->IsKilled() || !rigidBodyComp->entity->enabled) {
            continue;
        }

        auto worldPos = rigidBodyComp->entity->GetWorldPosition();
        auto worldOrientation = rigidBodyComp->entity->GetWorldOrientation();
        if (rigidBodyComp->IsKinematic()) {
            rigidBodyComp->SetPosition(worldPos);
            rigidBodyComp->SetOrientation(worldOrientation);
        } else if (rigidBodyComp->GetForceTransformSync()) {
            dynamicsWorld->removeRigidBody(rigidBodyComp->GetBulletRigidBody());
            rigidBodyComp->SetPosition(worldPos);
            rigidBodyComp->SetOrientation(worldOrientation);
            rigidBodyComp->GetBulletRigidBody()->activate(true); // To wake up from potentially sleeping state
            dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
            rigidBodyComp->SetForceTransformSync(false);
        }
    }

    dynamicsWorld->stepSimulation(deltaTime, 10);

    for (auto trigger : triggers) {
        trigger->Process(*dynamicsWorld);
    }
}

void PhysicsManager::UpdateEntityTransforms() {
    for (auto rigidBodyComp : rigidBodyComponents.GetAll()) {
        if (rigidBodyComp->IsKilled() || !rigidBodyComp->entity->enabled)
            continue;

        Entity* entity = rigidBodyComp->entity;
        auto trans = rigidBodyComp->GetBulletRigidBody()->getWorldTransform();
        entity->SetWorldPosition(Physics::btToGlm(trans.getOrigin()));
        entity->SetWorldOrientation(Physics::btToGlm(trans.getRotation()));
    }
}

void PhysicsManager::OnTriggerEnter(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](Physics::TriggerObserver& observer) {
            observer.OnEnter(callback);
        });
    });
}

void PhysicsManager::OnTriggerRetain(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](::Physics::TriggerObserver& observer) {
            observer.OnRetain(callback);
        });
    });
}

void PhysicsManager::OnTriggerLeave(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](::Physics::TriggerObserver& observer) {
            observer.OnLeave(callback);
        });
    });
}

Component::RigidBody* PhysicsManager::CreateRigidBody(Entity* owner) {
    auto comp = rigidBodyComponents.Create();
    comp->entity = owner;

    comp->NewBulletRigidBody(1.0f);

    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp) {
        comp->GetBulletRigidBody()->setCollisionShape(shapeComp->GetShape()->GetShape());
        comp->SetMass(1.0f);
        dynamicsWorld->addRigidBody(comp->GetBulletRigidBody());
    }

    return comp;
}

Component::RigidBody* PhysicsManager::CreateRigidBody(Entity* owner, const Json::Value& node) {
    auto comp = rigidBodyComponents.Create();
    comp->entity = owner;

    auto mass = node.get("mass", 1.0f).asFloat();
    comp->NewBulletRigidBody(mass);

    auto friction = node.get("friction", 0.5f).asFloat();
    comp->SetFriction(friction);

    auto rollingFriction = node.get("rollingFriction", 0.0f).asFloat();
    comp->SetRollingFriction(rollingFriction);

    auto spinningFriction = node.get("spinningFriction", 0.0f).asFloat();
    comp->SetSpinningFriction(spinningFriction);

    auto cor = node.get("cor", 0.0f).asFloat();
    comp->SetRestitution(cor);

    auto linearDamping = node.get("linearDamping", 0.0f).asFloat();
    comp->SetLinearDamping(linearDamping);

    auto kinematic = node.get("kinematic", false).asFloat();
    if (kinematic)
        comp->MakeKinematic();

    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp) {
        comp->GetBulletRigidBody()->setCollisionShape(shapeComp->GetShape()->GetShape());
        comp->SetMass(mass);
        dynamicsWorld->addRigidBody(comp->GetBulletRigidBody());
    }

    return comp;
}

Component::Shape* PhysicsManager::CreateShape(Entity* owner) {
    auto comp = shapeComponents.Create();
    comp->entity = owner;

    auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Sphere(1.0f)));
    comp->SetShape(shape);

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp) {
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
        rigidBodyComp->SetMass(rigidBodyComp->GetMass());
        dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
    }

    return comp;
}

Component::Shape* PhysicsManager::CreateShape(Entity* owner, const Json::Value& node) {
    auto comp = shapeComponents.Create();
    comp->entity = owner;

    if (node.isMember("sphere")) {
        auto sphere = node.get("sphere", {});
        auto radius = sphere.get("radius", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Sphere(radius)));
        comp->SetShape(shape);
    } else if (node.isMember("plane")) {
        auto plane = node.get("plane", {});
        auto normal = Json::LoadVec3(plane.get("normal", {}));
        auto planeCoeff = plane.get("planeCoeff", 0.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Plane(normal, planeCoeff)));
        comp->SetShape(shape);
    } else if (node.isMember("box")) {
        auto box = node.get("box", {});
        auto width = box.get("width", 1.0f).asFloat();
        auto height = box.get("height", 1.0f).asFloat();
        auto depth = box.get("depth", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Box(width, height, depth)));
        comp->SetShape(shape);
    } else if (node.isMember("cylinder")) {
        auto cylinder = node.get("cylinder", {});
        auto radius = cylinder.get("radius", 1.0f).asFloat();
        auto length = cylinder.get("length", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Cylinder(radius, length)));
        comp->SetShape(shape);
    } else if (node.isMember("cone")) {
        auto cone = node.get("cone", {});
        auto radius = cone.get("radius", 1.0f).asFloat();
        auto height = cone.get("height", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Cone(radius, height)));
        comp->SetShape(shape);
    } else if (node.isMember("capsule")) {
        auto capsule = node.get("capsule", {});
        auto radius = capsule.get("radius", 1.0f).asFloat();
        auto height = capsule.get("height", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Capsule(radius, height)));
        comp->SetShape(shape);
    }

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp) {
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
        rigidBodyComp->SetMass(rigidBodyComp->GetMass());
        dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
    }

    return comp;
}

Utility::LockBox<Physics::Trigger> PhysicsManager::CreateTrigger(Component::RigidBody* comp) {
    btTransform trans(btQuaternion(0, 0, 0, 1), ::Physics::glmToBt(comp->entity->position));
    Physics::Trigger* trigger = new Physics::Trigger(trans);
    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    trigger->SetCollisionShape(shapeComp ? shapeComp->GetShape() : nullptr);
    triggers.push_back(trigger);
    return Utility::LockBox<Physics::Trigger>(triggerLockBoxKey, trigger);
}

void PhysicsManager::SetShape(Component::Shape* comp, std::shared_ptr<::Physics::Shape> shape) {
    comp->SetShape(shape);

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp)
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
}

float PhysicsManager::GetMass(Component::RigidBody* comp) {
    return comp->GetMass();
}

void PhysicsManager::SetMass(Component::RigidBody* comp, float mass) {
    // Setting mass is only valid with a shape because it also sets inertia.
    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp)
        comp->SetMass(mass);
}

void PhysicsManager::SetFriction(Component::RigidBody* comp, float friction) {
    comp->SetFriction(friction);
}

void PhysicsManager::SetRollingFriction(Component::RigidBody* comp, float friction) {
    comp->SetRollingFriction(friction);
}

void PhysicsManager::SetSpinningFriction(Component::RigidBody* comp, float friction) {
    comp->SetSpinningFriction(friction);
}

void PhysicsManager::SetRestitution(Component::RigidBody* comp, float cor) {
    comp->SetRestitution(cor);
}

void PhysicsManager::SetLinearDamping(Component::RigidBody* comp, float damping) {
    comp->SetLinearDamping(damping);
}

void PhysicsManager::SetAngularDamping(Component::RigidBody* comp, float damping) {
    comp->SetAngularDamping(damping);
}

void PhysicsManager::MakeKinematic(Component::RigidBody* comp) {
    comp->MakeKinematic();
}

void PhysicsManager::MakeDynamic(Component::RigidBody* comp) {
    comp->MakeDynamic();
}

void PhysicsManager::ForceTransformSync(Component::RigidBody* comp) {
    comp->SetForceTransformSync(true);
}

const std::vector<Component::Shape*>& PhysicsManager::GetShapeComponents() const {
    return shapeComponents.GetAll();
}

void PhysicsManager::ClearKilledComponents() {
    rigidBodyComponents.ClearKilled(
        [this](Component::RigidBody* body) {
            dynamicsWorld->removeRigidBody(body->GetBulletRigidBody());
        });
    shapeComponents.ClearKilled();
}
<commit_msg>Load angular damping from JSON.<commit_after>#include "PhysicsManager.hpp"

#include <btBulletDynamicsCommon.h>
#include <glm/gtx/quaternion.hpp>
#include "../Component/RigidBody.hpp"
#include "../Component/Shape.hpp"
#include "../Entity/Entity.hpp"
#include "../Physics/GlmConversion.hpp"
#include "../Physics/Shape.hpp"
#include "../Physics/Trigger.hpp"
#include "../Physics/TriggerObserver.hpp"
#include "../Util/Json.hpp"

PhysicsManager::PhysicsManager() {
    // The broadphase is used to quickly cull bodies that will not collide with
    // each other, normally by leveraging some simpler (and rough) test such as
    // bounding boxes.
    broadphase = new btDbvtBroadphase;

    // With the collision configuration one can configure collision detection
    // algorithms.
    collisionConfiguration = new btDefaultCollisionConfiguration;
    dispatcher = new btCollisionDispatcher(collisionConfiguration);

    // The solver makes objects interact by making use of gravity, collisions,
    // game logic supplied forces, and constraints.
    solver = new btSequentialImpulseConstraintSolver;

    // The dynamics world encompasses objects included in the simulation.
    dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);

    // Y axis up
    dynamicsWorld->setGravity(btVector3(0, -9.82, 0));

    // Set the lockbox key we will use for lockboxes created in here.
    triggerLockBoxKey.reset(new Utility::LockBox<Physics::Trigger>::Key());
}

PhysicsManager::~PhysicsManager() {
    delete dynamicsWorld;
    delete solver;
    delete dispatcher;
    delete collisionConfiguration;
    delete broadphase;

    for (auto t : triggers)
        delete t;
}

void PhysicsManager::Update(float deltaTime) {
    for (auto rigidBodyComp : rigidBodyComponents.GetAll()) {
        if (rigidBodyComp->IsKilled() || !rigidBodyComp->entity->enabled) {
            continue;
        }

        auto worldPos = rigidBodyComp->entity->GetWorldPosition();
        auto worldOrientation = rigidBodyComp->entity->GetWorldOrientation();
        if (rigidBodyComp->IsKinematic()) {
            rigidBodyComp->SetPosition(worldPos);
            rigidBodyComp->SetOrientation(worldOrientation);
        } else if (rigidBodyComp->GetForceTransformSync()) {
            dynamicsWorld->removeRigidBody(rigidBodyComp->GetBulletRigidBody());
            rigidBodyComp->SetPosition(worldPos);
            rigidBodyComp->SetOrientation(worldOrientation);
            rigidBodyComp->GetBulletRigidBody()->activate(true); // To wake up from potentially sleeping state
            dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
            rigidBodyComp->SetForceTransformSync(false);
        }
    }

    dynamicsWorld->stepSimulation(deltaTime, 10);

    for (auto trigger : triggers) {
        trigger->Process(*dynamicsWorld);
    }
}

void PhysicsManager::UpdateEntityTransforms() {
    for (auto rigidBodyComp : rigidBodyComponents.GetAll()) {
        if (rigidBodyComp->IsKilled() || !rigidBodyComp->entity->enabled)
            continue;

        Entity* entity = rigidBodyComp->entity;
        auto trans = rigidBodyComp->GetBulletRigidBody()->getWorldTransform();
        entity->SetWorldPosition(Physics::btToGlm(trans.getOrigin()));
        entity->SetWorldOrientation(Physics::btToGlm(trans.getRotation()));
    }
}

void PhysicsManager::OnTriggerEnter(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](Physics::TriggerObserver& observer) {
            observer.OnEnter(callback);
        });
    });
}

void PhysicsManager::OnTriggerRetain(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](::Physics::TriggerObserver& observer) {
            observer.OnRetain(callback);
        });
    });
}

void PhysicsManager::OnTriggerLeave(Component::RigidBody* trigger, Component::RigidBody* object, std::function<void()> callback) {
    auto t = CreateTrigger(trigger);
    // Add the callback to the trigger observer
    t.Open(triggerLockBoxKey, [object, &callback](Physics::Trigger& trigger) {
        trigger.ForObserver(object->GetBulletRigidBody(), [&callback](::Physics::TriggerObserver& observer) {
            observer.OnLeave(callback);
        });
    });
}

Component::RigidBody* PhysicsManager::CreateRigidBody(Entity* owner) {
    auto comp = rigidBodyComponents.Create();
    comp->entity = owner;

    comp->NewBulletRigidBody(1.0f);

    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp) {
        comp->GetBulletRigidBody()->setCollisionShape(shapeComp->GetShape()->GetShape());
        comp->SetMass(1.0f);
        dynamicsWorld->addRigidBody(comp->GetBulletRigidBody());
    }

    return comp;
}

Component::RigidBody* PhysicsManager::CreateRigidBody(Entity* owner, const Json::Value& node) {
    auto comp = rigidBodyComponents.Create();
    comp->entity = owner;

    auto mass = node.get("mass", 1.0f).asFloat();
    comp->NewBulletRigidBody(mass);

    auto friction = node.get("friction", 0.5f).asFloat();
    comp->SetFriction(friction);

    auto rollingFriction = node.get("rollingFriction", 0.0f).asFloat();
    comp->SetRollingFriction(rollingFriction);

    auto spinningFriction = node.get("spinningFriction", 0.0f).asFloat();
    comp->SetSpinningFriction(spinningFriction);

    auto cor = node.get("cor", 0.0f).asFloat();
    comp->SetRestitution(cor);

    auto linearDamping = node.get("linearDamping", 0.0f).asFloat();
    comp->SetLinearDamping(linearDamping);

    auto angularDamping = node.get("angularDamping", 0.0f).asFloat();
    comp->SetAngularDamping(angularDamping);

    auto kinematic = node.get("kinematic", false).asFloat();
    if (kinematic)
        comp->MakeKinematic();

    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp) {
        comp->GetBulletRigidBody()->setCollisionShape(shapeComp->GetShape()->GetShape());
        comp->SetMass(mass);
        dynamicsWorld->addRigidBody(comp->GetBulletRigidBody());
    }

    return comp;
}

Component::Shape* PhysicsManager::CreateShape(Entity* owner) {
    auto comp = shapeComponents.Create();
    comp->entity = owner;

    auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Sphere(1.0f)));
    comp->SetShape(shape);

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp) {
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
        rigidBodyComp->SetMass(rigidBodyComp->GetMass());
        dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
    }

    return comp;
}

Component::Shape* PhysicsManager::CreateShape(Entity* owner, const Json::Value& node) {
    auto comp = shapeComponents.Create();
    comp->entity = owner;

    if (node.isMember("sphere")) {
        auto sphere = node.get("sphere", {});
        auto radius = sphere.get("radius", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Sphere(radius)));
        comp->SetShape(shape);
    } else if (node.isMember("plane")) {
        auto plane = node.get("plane", {});
        auto normal = Json::LoadVec3(plane.get("normal", {}));
        auto planeCoeff = plane.get("planeCoeff", 0.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Plane(normal, planeCoeff)));
        comp->SetShape(shape);
    } else if (node.isMember("box")) {
        auto box = node.get("box", {});
        auto width = box.get("width", 1.0f).asFloat();
        auto height = box.get("height", 1.0f).asFloat();
        auto depth = box.get("depth", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Box(width, height, depth)));
        comp->SetShape(shape);
    } else if (node.isMember("cylinder")) {
        auto cylinder = node.get("cylinder", {});
        auto radius = cylinder.get("radius", 1.0f).asFloat();
        auto length = cylinder.get("length", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Cylinder(radius, length)));
        comp->SetShape(shape);
    } else if (node.isMember("cone")) {
        auto cone = node.get("cone", {});
        auto radius = cone.get("radius", 1.0f).asFloat();
        auto height = cone.get("height", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Cone(radius, height)));
        comp->SetShape(shape);
    } else if (node.isMember("capsule")) {
        auto capsule = node.get("capsule", {});
        auto radius = capsule.get("radius", 1.0f).asFloat();
        auto height = capsule.get("height", 1.0f).asFloat();
        auto shape = std::shared_ptr<Physics::Shape>(new Physics::Shape(Physics::Shape::Capsule(radius, height)));
        comp->SetShape(shape);
    }

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp) {
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
        rigidBodyComp->SetMass(rigidBodyComp->GetMass());
        dynamicsWorld->addRigidBody(rigidBodyComp->GetBulletRigidBody());
    }

    return comp;
}

Utility::LockBox<Physics::Trigger> PhysicsManager::CreateTrigger(Component::RigidBody* comp) {
    btTransform trans(btQuaternion(0, 0, 0, 1), ::Physics::glmToBt(comp->entity->position));
    Physics::Trigger* trigger = new Physics::Trigger(trans);
    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    trigger->SetCollisionShape(shapeComp ? shapeComp->GetShape() : nullptr);
    triggers.push_back(trigger);
    return Utility::LockBox<Physics::Trigger>(triggerLockBoxKey, trigger);
}

void PhysicsManager::SetShape(Component::Shape* comp, std::shared_ptr<::Physics::Shape> shape) {
    comp->SetShape(shape);

    auto rigidBodyComp = comp->entity->GetComponent<Component::RigidBody>();
    if (rigidBodyComp)
        rigidBodyComp->GetBulletRigidBody()->setCollisionShape(comp->GetShape()->GetShape());
}

float PhysicsManager::GetMass(Component::RigidBody* comp) {
    return comp->GetMass();
}

void PhysicsManager::SetMass(Component::RigidBody* comp, float mass) {
    // Setting mass is only valid with a shape because it also sets inertia.
    auto shapeComp = comp->entity->GetComponent<Component::Shape>();
    if (shapeComp)
        comp->SetMass(mass);
}

void PhysicsManager::SetFriction(Component::RigidBody* comp, float friction) {
    comp->SetFriction(friction);
}

void PhysicsManager::SetRollingFriction(Component::RigidBody* comp, float friction) {
    comp->SetRollingFriction(friction);
}

void PhysicsManager::SetSpinningFriction(Component::RigidBody* comp, float friction) {
    comp->SetSpinningFriction(friction);
}

void PhysicsManager::SetRestitution(Component::RigidBody* comp, float cor) {
    comp->SetRestitution(cor);
}

void PhysicsManager::SetLinearDamping(Component::RigidBody* comp, float damping) {
    comp->SetLinearDamping(damping);
}

void PhysicsManager::SetAngularDamping(Component::RigidBody* comp, float damping) {
    comp->SetAngularDamping(damping);
}

void PhysicsManager::MakeKinematic(Component::RigidBody* comp) {
    comp->MakeKinematic();
}

void PhysicsManager::MakeDynamic(Component::RigidBody* comp) {
    comp->MakeDynamic();
}

void PhysicsManager::ForceTransformSync(Component::RigidBody* comp) {
    comp->SetForceTransformSync(true);
}

const std::vector<Component::Shape*>& PhysicsManager::GetShapeComponents() const {
    return shapeComponents.GetAll();
}

void PhysicsManager::ClearKilledComponents() {
    rigidBodyComponents.ClearKilled(
        [this](Component::RigidBody* body) {
            dynamicsWorld->removeRigidBody(body->GetBulletRigidBody());
        });
    shapeComponents.ClearKilled();
}
<|endoftext|>


<commit_before>// Loosely based on https://repo.anl-external.org/repos/BlueTBB/tbb30_104oss/src/rml/perfor/tbb_simple.cpp

// #include "stdafx.h"

// int _tmain(int argc, _TCHAR* argv[])
// {
//	return 0;
// }

#include "tbb/task_group.h"

#include <iostream>
#include <stdio.h> //// MOVE TO iostreams TODO
#include <stdlib.h>

//#include <chrono> // for 2s to mean 2 seconds
//using namespace std::literals::chrono_literals; // as above
//#include <thread> // for std::this_thread::sleep_for(1);

#include <tbb/mutex.h>
#include <tbb/tbb_thread.h>

// tbb::mutex my_mutex;

#if _WIN32||_WIN64
//#include <Windows.h> /* Sleep */
#else
//// #error Only tested on Windows! TODO
// #include <unistd.h>  /* usleep */
#endif

using namespace tbb;

#if 0 // totally inappropriate and broken use of subclassing of tbb::task, just for giggles
// see https://www.threadingbuildingblocks.org/docs/help/reference/task_scheduler/task_cls.htm
#include "tbb/task.h"

class TrivialTask : public tbb::task {
public:

    TrivialTask() {	}

    task* parent() const { // the "parent" member-function is confusingly referred to as "the successor attribute"
        return NULL;
    }

    task* execute() override {
        puts("Hello from my task!");
        return NULL;
    }

    ~TrivialTask() {
        puts("Destroying my task");
    }
};

// allocate_continuation
// #include <stdio.h>
// #include <stdlib.h>
int main(int argc, char *argv[]) {
    // use TBB's custom allocator, along the lines shown in
    // https://www.threadingbuildingblocks.org/docs/help/tbb_userguide/Simple_Example_Fibonacci_Numbers.htm#tutorial_Simple_Example_Fibonacci_Numbers

    // see also https://www.threadingbuildingblocks.org/docs/help/reference/task_scheduler/task_allocation.htm

    {
        // looking at task_allocation.htm this should use:
        // "cancellation group is the current innermost cancellation group. "
        ////// WHICH WE DON'T HAVE!?!?! shouldn't this cause an assert failure?
        task& t = *new(task::allocate_root()) TrivialTask; // following http://fulla.fnal.gov/intel/tbb/html/a00249.html

        auto count1 = t.ref_count();

        t.execute(); // No concurrency! Hence 'totally inappropriate'
                     // t.decrement_ref_count(); causes underflow!
                     //if ( NULL != t.parent ) {
                     //}

                     // "Because there is no placement delete expression[...]" https://en.wikipedia.org/w/index.php?title=Placement_syntax&oldid=674756226#Custom_allocators

                     // not using standard 'new' so can't use standard 'delete'
                     //delete (task::allocate_root()) &t; // kaboom! VS2010 picks up a double-free problem. Looks like we're missing something important....????

        auto count2 = t.ref_count();

        t.decrement_ref_count(); // same as   t.set_ref_count(0);

    }

    return EXIT_SUCCESS;
}
#endif

#if 0
int main(int argc, char *argv[]) {
    puts("Starting...");

    task_group g;

    g.run([&] {Sleep(2000); puts("Task 1 is away"); });
    g.run([&] {Sleep(2000); puts("Task 2 is away"); });
    g.run([&] {Sleep(2000); puts("Task 3 is away"); });

    g.run_and_wait([&] {Sleep(2000); puts("A message from the main thread"); });

    //////g.wait();
    // getchar();
    return EXIT_SUCCESS;
}
#endif

// demonstrate the const issue with run_and_wait
#if 0
int main(int argc, char *argv[]) {
    puts("Starting main thread...");

    class MyCallable {
    public:
      MyCallable() {} // clang++ doesn't like 'const' instance of empty class without explicitly defined constructor
// Normally, using an empty class we avoid having to define our own default constructor
// (even if MSVC is permissive here) see http://stackoverflow.com/a/8092791/2307853
//    int dummy;

        void operator()() const {
            puts("Task is running");
        }
    };

    const MyCallable f;

    {
        task_group g;

        // g.run( f ); g.wait();
        g.run_and_wait( f );

//      g.run_and_wait( [&]() { f(); } );
//      g.run_and_wait( [&]() { } );
        // C++ lambdas seem to survive the const shenanigans, but MyCallable doesn't: build error
    }

    puts("Press Enter to exit");
    getchar();
    return EXIT_SUCCESS;
}
#endif

#if 1 // fun with the idea of futures

// #include "tbb/atomic.h"

// Faking/implementing futures with TBB tasks

// Note that mutable state is held in its own struct,
// as TBB's run(1) function accepts its arg by const reference,
// forcing us to handle mutation via a pointer to a mutable value
// and not within the MyFuture class itself.

// we use TBB's 'sleep' functionality, to avoid C++14 dependency
const tbb::tick_count::interval_t oneSecond(1.0);    // double holds the number of seconds
const tbb::tick_count::interval_t threeSeconds(3.0);
const tbb::tick_count::interval_t tenSeconds(10.0);

int main(int argc, char *argv[]) {
    puts("Starting...");

    class MyFuture {
    public:

        struct MutableState {
          MutableState(int r) : result(r) { }
          int result;
        };

        task_group * tgPtr;
        MutableState * msPtr;

        MyFuture(task_group *t, MutableState * m) :
            tgPtr(t),
            msPtr(m)
        { }

        void operator()() const {
            puts("[from task] Task is running. Now for the pause...");
//          this_tbb_thread::sleep( threeSeconds );
            this_tbb_thread::sleep( tenSeconds );
            puts("[from task] Task pause complete, assigning output...");
            msPtr->result = 3;
            return;
        }

        int getResult() const {
            tgPtr->wait();
            return msPtr->result;
        }

    };

    int modifyMe = 0;

    MyFuture::MutableState ms(0);

    task_group g;

    const MyFuture f(&g, &ms);

//  g.run_and_wait( [&](){f();} );

    puts("Now to run");
    g.run(f);
    puts("Running. Now to do a couple of prints with a pause between each.");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after a second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after another second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after yet another second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after yet another second");

    puts("And now to wait...");
    g.wait();

    printf( "%d\n", f.getResult() );

    //g.run( [&]{Sleep(2000);puts("Task 1 is away");} );
    //g.run( [&]{Sleep(2000);puts("Task 2 is away");} );
    //g.run( [&]{Sleep(2000);puts("Task 3 is away");} );

    //g.run_and_wait( [&]{Sleep(2000); puts("A message from the main thread");} );

    //////g.wait();
    // getchar();
    return EXIT_SUCCESS;
}
#endif

#if 0 // the fib example from the web
int fib(int n) {
    int ret;
    if (n < 2) {
        ret = n;
    }
    else {
        int x, y;
        task_group g;

        x = y = 9;

        // g.run( [&]{my_mutex.lock();/* x=fib(n-1); */ puts("Now:\n"); getchar(); my_mutex.unlock();} ); // spawn a task

        g.run([&] {
            tbb::mutex::scoped_lock lock(my_mutex);
            /* x=fib(n-1); */ puts("Now:\n"); getchar();
        }); // spawn a task

            // g.run( [&]{my_mutex.lock();/* y=fib(n-2); */ puts("Now:\n"); getchar(); my_mutex.unlock();} ); // spawn another task
        g.run([&] {
            tbb::mutex::scoped_lock lock(my_mutex);/* y=fib(n-2); */ puts("Now:\n"); getchar();
        }); // spawn another task

        g.wait();                // wait for both tasks to complete

        ret = x + y;
    }

    return ret;
} // - See more at: https://www.threadingbuildingblocks.org/tutorial-intel-tbb-task-based-programming#sthash.EzgRXzaB.dpuf

int main(int argc, char *argv[]) {
    std::cout << fib(33);

    // getchar();
    return EXIT_SUCCESS;
}

#endif
<commit_msg>Make private our two members<commit_after>// Loosely based on https://repo.anl-external.org/repos/BlueTBB/tbb30_104oss/src/rml/perfor/tbb_simple.cpp

// #include "stdafx.h"

// int _tmain(int argc, _TCHAR* argv[])
// {
//	return 0;
// }

#include "tbb/task_group.h"

#include <iostream>
#include <stdio.h> //// MOVE TO iostreams TODO
#include <stdlib.h>

//#include <chrono> // for 2s to mean 2 seconds
//using namespace std::literals::chrono_literals; // as above
//#include <thread> // for std::this_thread::sleep_for(1);

#include <tbb/mutex.h>
#include <tbb/tbb_thread.h>

// tbb::mutex my_mutex;

#if _WIN32||_WIN64
//#include <Windows.h> /* Sleep */
#else
//// #error Only tested on Windows! TODO
// #include <unistd.h>  /* usleep */
#endif

using namespace tbb;

#if 0 // totally inappropriate and broken use of subclassing of tbb::task, just for giggles
// see https://www.threadingbuildingblocks.org/docs/help/reference/task_scheduler/task_cls.htm
#include "tbb/task.h"

class TrivialTask : public tbb::task {
public:

    TrivialTask() {	}

    task* parent() const { // the "parent" member-function is confusingly referred to as "the successor attribute"
        return NULL;
    }

    task* execute() override {
        puts("Hello from my task!");
        return NULL;
    }

    ~TrivialTask() {
        puts("Destroying my task");
    }
};

// allocate_continuation
// #include <stdio.h>
// #include <stdlib.h>
int main(int argc, char *argv[]) {
    // use TBB's custom allocator, along the lines shown in
    // https://www.threadingbuildingblocks.org/docs/help/tbb_userguide/Simple_Example_Fibonacci_Numbers.htm#tutorial_Simple_Example_Fibonacci_Numbers

    // see also https://www.threadingbuildingblocks.org/docs/help/reference/task_scheduler/task_allocation.htm

    {
        // looking at task_allocation.htm this should use:
        // "cancellation group is the current innermost cancellation group. "
        ////// WHICH WE DON'T HAVE!?!?! shouldn't this cause an assert failure?
        task& t = *new(task::allocate_root()) TrivialTask; // following http://fulla.fnal.gov/intel/tbb/html/a00249.html

        auto count1 = t.ref_count();

        t.execute(); // No concurrency! Hence 'totally inappropriate'
                     // t.decrement_ref_count(); causes underflow!
                     //if ( NULL != t.parent ) {
                     //}

                     // "Because there is no placement delete expression[...]" https://en.wikipedia.org/w/index.php?title=Placement_syntax&oldid=674756226#Custom_allocators

                     // not using standard 'new' so can't use standard 'delete'
                     //delete (task::allocate_root()) &t; // kaboom! VS2010 picks up a double-free problem. Looks like we're missing something important....????

        auto count2 = t.ref_count();

        t.decrement_ref_count(); // same as   t.set_ref_count(0);

    }

    return EXIT_SUCCESS;
}
#endif

#if 0
int main(int argc, char *argv[]) {
    puts("Starting...");

    task_group g;

    g.run([&] {Sleep(2000); puts("Task 1 is away"); });
    g.run([&] {Sleep(2000); puts("Task 2 is away"); });
    g.run([&] {Sleep(2000); puts("Task 3 is away"); });

    g.run_and_wait([&] {Sleep(2000); puts("A message from the main thread"); });

    //////g.wait();
    // getchar();
    return EXIT_SUCCESS;
}
#endif

// demonstrate the const issue with run_and_wait
#if 0
int main(int argc, char *argv[]) {
    puts("Starting main thread...");

    class MyCallable {
    public:
      MyCallable() {} // clang++ doesn't like 'const' instance of empty class without explicitly defined constructor
// Normally, using an empty class we avoid having to define our own default constructor
// (even if MSVC is permissive here) see http://stackoverflow.com/a/8092791/2307853
//    int dummy;

        void operator()() const {
            puts("Task is running");
        }
    };

    const MyCallable f;

    {
        task_group g;

        // g.run( f ); g.wait();
        g.run_and_wait( f );

//      g.run_and_wait( [&]() { f(); } );
//      g.run_and_wait( [&]() { } );
        // C++ lambdas seem to survive the const shenanigans, but MyCallable doesn't: build error
    }

    puts("Press Enter to exit");
    getchar();
    return EXIT_SUCCESS;
}
#endif

#if 1 // fun with the idea of futures

// #include "tbb/atomic.h"

// Faking/implementing futures with TBB tasks

// Note that mutable state is held in its own struct,
// as TBB's run(1) function accepts its arg by const reference,
// forcing us to handle mutation via a pointer to a mutable value
// and not within the MyFuture class itself.

// we use TBB's 'sleep' functionality, to avoid C++14 dependency
const tbb::tick_count::interval_t oneSecond(1.0);    // double holds the number of seconds
const tbb::tick_count::interval_t threeSeconds(3.0);
const tbb::tick_count::interval_t tenSeconds(10.0);

int main(int argc, char *argv[]) {
    puts("Starting...");

    class MyFuture {
    public:
        struct MutableState {
          MutableState(int r) : result(r) { }
          int result;
        };

    private:
        task_group   * tgPtr;
        MutableState * msPtr;

    public:
        MyFuture(task_group *t, MutableState * m) :
            tgPtr(t),
            msPtr(m)
        { }

        void operator()() const {
            puts("[from task] Task is running. Now for the pause...");
//          this_tbb_thread::sleep( threeSeconds );
            this_tbb_thread::sleep( tenSeconds );
            puts("[from task] Task pause complete, assigning output...");
            msPtr->result = 3;
            return;
        }

        int getResult() const {
            tgPtr->wait();
            return msPtr->result;
        }

    };

    int modifyMe = 0;

    MyFuture::MutableState ms(0);

    task_group g;

    const MyFuture f(&g, &ms);

//  g.run_and_wait( [&](){f();} );

    puts("Now to run");
    g.run(f);
    puts("Running. Now to do a couple of prints with a pause between each.");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after a second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after another second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after yet another second");
    this_tbb_thread::sleep( oneSecond );
    puts("And here we are after yet another second");

    puts("And now to wait...");
    g.wait();

    printf( "%d\n", f.getResult() );

    //g.run( [&]{Sleep(2000);puts("Task 1 is away");} );
    //g.run( [&]{Sleep(2000);puts("Task 2 is away");} );
    //g.run( [&]{Sleep(2000);puts("Task 3 is away");} );

    //g.run_and_wait( [&]{Sleep(2000); puts("A message from the main thread");} );

    //////g.wait();
    // getchar();
    return EXIT_SUCCESS;
}
#endif

#if 0 // the fib example from the web
int fib(int n) {
    int ret;
    if (n < 2) {
        ret = n;
    }
    else {
        int x, y;
        task_group g;

        x = y = 9;

        // g.run( [&]{my_mutex.lock();/* x=fib(n-1); */ puts("Now:\n"); getchar(); my_mutex.unlock();} ); // spawn a task

        g.run([&] {
            tbb::mutex::scoped_lock lock(my_mutex);
            /* x=fib(n-1); */ puts("Now:\n"); getchar();
        }); // spawn a task

            // g.run( [&]{my_mutex.lock();/* y=fib(n-2); */ puts("Now:\n"); getchar(); my_mutex.unlock();} ); // spawn another task
        g.run([&] {
            tbb::mutex::scoped_lock lock(my_mutex);/* y=fib(n-2); */ puts("Now:\n"); getchar();
        }); // spawn another task

        g.wait();                // wait for both tasks to complete

        ret = x + y;
    }

    return ret;
} // - See more at: https://www.threadingbuildingblocks.org/tutorial-intel-tbb-task-based-programming#sthash.EzgRXzaB.dpuf

int main(int argc, char *argv[]) {
    std::cout << fib(33);

    // getchar();
    return EXIT_SUCCESS;
}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Win32/IconImpl.hpp>
#include <Nazara/Utility/Image.hpp>
#include <Nazara/Utility/Debug.hpp>

bool NzIconImpl::Create(const NzImage& icon)
{
	NzImage windowsIcon(icon);
	if (!windowsIcon.Convert(nzPixelFormat_BGRA8))
	{
		NazaraError("Failed to convert icon to BGRA8");
		return false;
	}

	HBITMAP bitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 32, windowsIcon.GetConstPixels());
	HBITMAP monoBitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 1, nullptr);

	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx
	ICONINFO iconInfo;
	iconInfo.fIcon = TRUE;
	iconInfo.hbmMask = monoBitmap;
	iconInfo.hbmColor = bitmap;

	m_icon = CreateIconIndirect(&iconInfo);

	DeleteObject(bitmap);
	DeleteObject(monoBitmap);

	if (!m_icon)
	{
		NazaraError("Failed to create icon: " + NzGetLastSystemError());
		return false;
	}

	return true;
}

void NzIconImpl::Destroy()
{
	DestroyIcon(m_icon);
}

HICON NzIconImpl::GetIcon()
{
	return m_icon;
}
<commit_msg>Added comment<commit_after>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Win32/IconImpl.hpp>
#include <Nazara/Utility/Image.hpp>
#include <Nazara/Utility/Debug.hpp>

bool NzIconImpl::Create(const NzImage& icon)
{
	NzImage windowsIcon(icon); // Vive le COW
	if (!windowsIcon.Convert(nzPixelFormat_BGRA8))
	{
		NazaraError("Failed to convert icon to BGRA8");
		return false;
	}

	HBITMAP bitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 32, windowsIcon.GetConstPixels());
	HBITMAP monoBitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 1, nullptr);

	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx
	ICONINFO iconInfo;
	iconInfo.fIcon = TRUE;
	iconInfo.hbmMask = monoBitmap;
	iconInfo.hbmColor = bitmap;

	m_icon = CreateIconIndirect(&iconInfo);

	DeleteObject(bitmap);
	DeleteObject(monoBitmap);

	if (!m_icon)
	{
		NazaraError("Failed to create icon: " + NzGetLastSystemError());
		return false;
	}

	return true;
}

void NzIconImpl::Destroy()
{
	DestroyIcon(m_icon);
}

HICON NzIconImpl::GetIcon()
{
	return m_icon;
}
<|endoftext|>


<commit_before>#include "MemoryHandler.hpp" //MemoryHandler class

class Trainer //trainer class, resposable for the cheats itself
{

public:
	MemoryHandler memory; //MemoryHandler

	enum //enumerates all the static address, dynamic address needed to be defined using another way
	{
		TRAINER_LIFE = 0xB793E0,
		TRAINER_MONEY = 0xB7CE50, //money address
		TRAINER_WANTED = 0xBAA420 //Wanted Level Adress
		/*
		TRAINER_ARMOR = 0xB6F5F0 + 0x548, -> dynamic
		TRAINER_X, -> dynamic
		TRAINER_Y, -> dynamic
		TRAINER_Z, -> dynamic
		TRAINER_SCORE -> don't know if exists
		*/
	};

	void SetLife(float life);
	void SetMoney(int money);
	void SetArmor(float armor);
	void SetWantedLevel(int level);
	/*
	void SetX(double pos);
	void SetY(double pos);
	void SetZ(double pos);
	void SetPos(double x,double y, double z);
	void SetScore(int score);
	*/
};
<commit_msg>ADDED INTERFACE COLOR OFFSETS/ADDRESSES<commit_after>#include "MemoryHandler.hpp" //MemoryHandler class

class Trainer //trainer class, resposable for the cheats itself
{

public:
	MemoryHandler memory; //MemoryHandler

	enum //enumerates all the static address, dynamic address needed to be defined using another way
	{
		TRAINER_LIFE = 0xB793E0,
		TRAINER_MONEY = 0xB7CE50, //money address
		TRAINER_WANTED = 0xBAA420, //Wanted Level Adress

		//Interface address, which represents health bar/red text/enemy marker/anything red color
		//initial Address = 0xBAB22C 4 bytes of RGBA.
		TRAINER_RED = 0xBAB22C,			//red color, pointed on the initial address
		TRAINER_BLUE = TRAINER_RED + 1,		//blue color, pointed on the second byte of the address
		TRAINER_GREEN = TRAINER_RED + 2,	//green color, pointed on the third byte of the address
		TRAINER_ALPHA = TRAINER_RED + 3		//alpha, pointed on the last byte of the address
		/*
		TRAINER_ARMOR = 0xB6F5F0 + 0x548, -> dynamic
		TRAINER_X, -> dynamic
		TRAINER_Y, -> dynamic
		TRAINER_Z, -> dynamic
		TRAINER_SCORE -> don't know if exists
		*/
	};

	void SetLife(float life);
	void SetMoney(int money);
	void SetArmor(float armor);
	void SetWantedLevel(int level);
	/*
	void SetX(double pos);
	void SetY(double pos);
	void SetZ(double pos);
	void SetPos(double x,double y, double z);
	void SetScore(int score);
	*/
};
<|endoftext|>