<commit_before>//
//  ofxWater.cpp
//
//  Created by Patricio Gonzalez Vivo on 9/26/11.
//  Copyright 2011 http://www.patriciogonzalezvivo.com/ All rights reserved.
//

#include "ofxWater.h"

ofxWater::ofxWater(){
    passes = 1;
    internalFormat = GL_RGB;

    density = 1.0;
    velocity = 1.0;

    fragmentShader = STRINGIFY(
    uniform sampler2DRect backbuffer;   // previus buffer
    uniform sampler2DRect tex0;         // actual buffer

    //  This two are not going to be used in this shader
    //  but are need to tell ofxFXObject that need to create them
    //
    uniform sampler2DRect tex1;         // is going to be the background
    uniform sampler2DRect tex2;         // is going to be the render FBO

    uniform float damping;
    uniform float velocity;

    vec2 offset[4];

    void main(){
        vec2 st = gl_TexCoord[0].st;

        offset[0] = vec2(-velocity, 0.0);
        offset[1] = vec2(velocity, 0.0);
        offset[2] = vec2(0.0, velocity);
        offset[3] = vec2(0.0, -velocity);

        //  Grab the information arround the active pixel
        //
        //      [3]
        //
        //  [0]  st  [1]
        //
        //      [2]

        vec3 sum = vec3(0.0, 0.0, 0.0);

        for (int i = 0; i < 4 ; i++){
            sum += texture2DRect(tex0, st + offset[i]).rgb;
        }

        //  make an average and substract the center value
        //
        sum = (sum / 2.0) - texture2DRect(backbuffer, st).rgb;
        sum *= damping;

        gl_FragColor = vec4(sum, 1.0);
    } );
    shader.unload();
    shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentShader);
    shader.linkProgram();

    // This map the desplacement to the background
    //
    string fragmentRenderShader = STRINGIFY(
    uniform sampler2DRect tex0; //  background
    uniform sampler2DRect tex1; //  displacement

    void main(){
        vec2 st = gl_TexCoord[0].st;

        float offsetX = texture2DRect(tex1, st + vec2(-1.0, 0.0)).r - texture2DRect(tex1, st + vec2(1.0, 0.0)).r;
        float offsetY = texture2DRect(tex1, st + vec2(0.0,- 1.0)).r - texture2DRect(tex1, st + vec2(0.0, 1.0)).r;

        float shading = offsetX;

        vec3 pixel = texture2DRect(tex0, st + vec2(offsetX, offsetY)).rgb;

        pixel.r += shading;
        pixel.g += shading;
        pixel.b += shading;

        gl_FragColor.rgb =  pixel;
        gl_FragColor.a = 1.0;
    } );
    renderShader.unload();
    renderShader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentRenderShader);
    renderShader.linkProgram();

    // Fast Blur Shader
    //
    string fragmentBlurShader = STRINGIFY(
    uniform sampler2DRect tex1;
    float fade_const = 0.000001;

    float kernel[9];
    vec2 offset[9];

    void main(void){
        vec2  st = gl_TexCoord[0].st;
        vec4 sum = vec4(0.0);

        offset[0] = vec2(-1.0, -1.0);
        offset[1] = vec2(0.0, -1.0);
        offset[2] = vec2(1.0, -1.0);

        offset[3] = vec2(-1.0, 0.0);
        offset[4] = vec2(0.0, 0.0);
        offset[5] = vec2(1.0, 0.0);

        offset[6] = vec2(-1.0, 1.0);
        offset[7] = vec2(0.0, 1.0);
        offset[8] = vec2(1.0, 1.0);

        kernel[0] = 1.0/16.0;   kernel[1] = 2.0/16.0;   kernel[2] = 1.0/16.0;
        kernel[3] = 2.0/16.0;   kernel[4] = 4.0/16.0;   kernel[5] = 2.0/16.0;
        kernel[6] = 1.0/16.0;   kernel[7] = 2.0/16.0;   kernel[8] = 1.0/16.0;

        int i = 0;
        for (i = 0; i < 4; i++){
            vec4 tmp = texture2DRect(tex1, st + offset[i]);
            sum += tmp * kernel[i];
        }

        for (i = 5; i < 9; i++){
            vec4 tmp = texture2DRect(tex1, st + offset[i]);
            sum += tmp * kernel[i];
        }

        vec4 color0 = texture2DRect(tex1, st + offset[4]);
            sum += color0 * kernel[4];

        gl_FragColor = (1.0 - fade_const) * color0 +  fade_const * vec4(sum.rgb, color0.a);
    }
                                          );
    blurShader.unload();
    blurShader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentBlurShader);
    blurShader.linkProgram();
}

ofxWater& ofxWater::loadBackground(string file){
    ofImage backgroundImage;
    backgroundImage.loadImage(file);
    allocate(backgroundImage.getWidth(), backgroundImage.getHeight());

    textures[0].begin();
    backgroundImage.draw(0,0);
    textures[0].end();

    return * this;
}

ofxWater& ofxWater::linkBackground(ofTexture * _backText){
    textures[0].begin();
    _backText->draw(0,0);
    textures[0].end();

    return * this;
}

void ofxWater::begin() {
    ofPushStyle();
    ofPushMatrix();
    pingPong.src->begin();
}

void ofxWater::end() {
    pingPong.src->end();
    ofPopMatrix();
    ofPopStyle();
}

void ofxWater::update(){
    // Calculate the difference between buffers and spread the waving
    textures[1].begin();
    ofClear(0);
    shader.begin();
    shader.setUniformTexture("backbuffer", pingPong.dst->getTextureReference(), 0);
    shader.setUniformTexture("tex0", pingPong.src->getTextureReference(), 1);
    shader.setUniform1f("damping", (float)density );
    shader.setUniform1f("velocity", (float)velocity);
    renderFrame();
    shader.end();
    textures[1].end();

    // Blur the waving in order to make it smooth
    pingPong.dst->begin();
    blurShader.begin();
    blurShader.setUniformTexture("tex1", textures[1].getTextureReference(), 0);
    renderFrame();
    blurShader.end();
    pingPong.dst->end();

    // Use the buffer as a bumpmap to morph the surface of the background texture
    textures[2].begin();
    ofClear(0);
    renderShader.begin();
    renderShader.setUniformTexture("tex0", textures[0].getTextureReference(), 0);
    renderShader.setUniformTexture("tex1", textures[1].getTextureReference(), 1);
    renderFrame();
    renderShader.end();
    textures[2].end();

    // Switch buffers
    pingPong.swap();
}

void ofxWater::draw(int x, int y, float _width, float _height){
    if (_width == -1) _width = width;
    if (_height == -1) _height = height;
    textures[2].draw(x,y, _width, _height);
}

<commit_msg>press to se bounceMap<commit_after>//
//  ofxWater.cpp
//
//  Created by Patricio Gonzalez Vivo on 9/26/11.
//  Copyright 2011 http://www.patriciogonzalezvivo.com/ All rights reserved.
//

#include "ofxWater.h"

ofxWater::ofxWater(){
    passes = 1;
    internalFormat = GL_RGB;

    density = 1.0;
    velocity = 1.0;

    fragmentShader = STRINGIFY(
    uniform sampler2DRect backbuffer;   // previus buffer
    uniform sampler2DRect tex0;         // actual buffer

    //  This two are not going to be used in this shader
    //  but are need to tell ofxFXObject that need to create them
    //
    uniform sampler2DRect tex1;         // is going to be the background
    uniform sampler2DRect tex2;         // is going to be the render FBO

    uniform float damping;
    uniform float velocity;

    vec2 offset[4];

    void main(){
        vec2 st = gl_TexCoord[0].st;

        offset[0] = vec2(-velocity, 0.0);
        offset[1] = vec2(velocity, 0.0);
        offset[2] = vec2(0.0, velocity);
        offset[3] = vec2(0.0, -velocity);

        //  Grab the information arround the active pixel
        //
        //      [3]
        //
        //  [0]  st  [1]
        //
        //      [2]

        vec3 sum = vec3(0.0, 0.0, 0.0);

        for (int i = 0; i < 4 ; i++){
            sum += texture2DRect(tex0, st + offset[i]).rgb;
        }

        //  make an average and substract the center value
        //
        sum = (sum / 2.0) - texture2DRect(backbuffer, st).rgb;
        sum *= damping;

        gl_FragColor = vec4(sum, 1.0);
    } );
    shader.unload();
    shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentShader);
    shader.linkProgram();

    // This map the desplacement to the background
    //
    string fragmentRenderShader = STRINGIFY(
    uniform sampler2DRect tex0; //  background
    uniform sampler2DRect tex1; //  displacement

    void main(){
        vec2 st = gl_TexCoord[0].st;

        float offsetX = texture2DRect(tex1, st + vec2(-1.0, 0.0)).r - texture2DRect(tex1, st + vec2(1.0, 0.0)).r;
        float offsetY = texture2DRect(tex1, st + vec2(0.0,- 1.0)).r - texture2DRect(tex1, st + vec2(0.0, 1.0)).r;

        float shading = offsetX;

        vec3 pixel = texture2DRect(tex0, st + vec2(offsetX, offsetY)).rgb;

        pixel.r += shading;
        pixel.g += shading;
        pixel.b += shading;

        gl_FragColor.rgb =  pixel;
        gl_FragColor.a = 1.0;
    } );
    renderShader.unload();
    renderShader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentRenderShader);
    renderShader.linkProgram();

    // Fast Blur Shader
    //
    string fragmentBlurShader = STRINGIFY(
    uniform sampler2DRect tex1;
    float fade_const = 0.000005;

    float kernel[9];
    vec2 offset[9];

    void main(void){
        vec2  st = gl_TexCoord[0].st;
        vec4 sum = vec4(0.0);

        offset[0] = vec2(-1.0, -1.0);
        offset[1] = vec2(0.0, -1.0);
        offset[2] = vec2(1.0, -1.0);

        offset[3] = vec2(-1.0, 0.0);
        offset[4] = vec2(0.0, 0.0);
        offset[5] = vec2(1.0, 0.0);

        offset[6] = vec2(-1.0, 1.0);
        offset[7] = vec2(0.0, 1.0);
        offset[8] = vec2(1.0, 1.0);

        kernel[0] = 1.0/16.0;   kernel[1] = 2.0/16.0;   kernel[2] = 1.0/16.0;
        kernel[3] = 2.0/16.0;   kernel[4] = 4.0/16.0;   kernel[5] = 2.0/16.0;
        kernel[6] = 1.0/16.0;   kernel[7] = 2.0/16.0;   kernel[8] = 1.0/16.0;

        int i = 0;
        for (i = 0; i < 4; i++){
            vec4 tmp = texture2DRect(tex1, st + offset[i]);
            sum += tmp * kernel[i];
        }

        for (i = 5; i < 9; i++){
            vec4 tmp = texture2DRect(tex1, st + offset[i]);
            sum += tmp * kernel[i];
        }

        vec4 color0 = texture2DRect(tex1, st + offset[4]);
            sum += color0 * kernel[4];

        gl_FragColor = (1.0 - fade_const) * color0 +  fade_const * vec4(sum.rgb, color0.a);
    }
                                          );
    blurShader.unload();
    blurShader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentBlurShader);
    blurShader.linkProgram();
}

ofxWater& ofxWater::loadBackground(string file){
    ofImage backgroundImage;
    backgroundImage.loadImage(file);
    allocate(backgroundImage.getWidth(), backgroundImage.getHeight());

    textures[0].begin();
    backgroundImage.draw(0,0);
    textures[0].end();

    return * this;
}

ofxWater& ofxWater::linkBackground(ofTexture * _backText){
    textures[0].begin();
    _backText->draw(0,0);
    textures[0].end();

    return * this;
}

void ofxWater::begin() {
    ofPushStyle();
    ofPushMatrix();
    pingPong.src->begin();
}

void ofxWater::end() {
    pingPong.src->end();
    ofPopMatrix();
    ofPopStyle();
}

void ofxWater::update(){
    // Calculate the difference between buffers and spread the waving
    textures[1].begin();
    ofClear(0);
    shader.begin();
    shader.setUniformTexture("backbuffer", pingPong.dst->getTextureReference(), 0);
    shader.setUniformTexture("tex0", pingPong.src->getTextureReference(), 1);
    shader.setUniform1f("damping", (float)density );
    shader.setUniform1f("velocity", (float)velocity);
    renderFrame();
    shader.end();
    textures[1].end();

    // Blur the waving in order to make it smooth
    pingPong.dst->begin();
    blurShader.begin();
    blurShader.setUniformTexture("tex1", textures[1].getTextureReference(), 0);
    renderFrame();
    blurShader.end();
    pingPong.dst->end();

    // Use the buffer as a bumpmap to morph the surface of the background texture
    textures[2].begin();
    ofClear(0);
    renderShader.begin();
    renderShader.setUniformTexture("tex0", textures[0].getTextureReference(), 0);
    renderShader.setUniformTexture("tex1", textures[1].getTextureReference(), 1);
    renderFrame();
    renderShader.end();
    textures[2].end();

    // Switch buffers
    pingPong.swap();
}

void ofxWater::draw(int x, int y, float _width, float _height){
    if (_width == -1) _width = width;
    if (_height == -1) _height = height;
    textures[2].draw(x,y, _width, _height);
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script.h"

#include "tinyformat.h"
#include "utilstrencodings.h"

using namespace std;

const char* GetOpName(opcodetype opcode)
{
    switch (opcode)
    {
    // push value
    case OP_0                      : return "0";
    case OP_PUSHDATA1              : return "OP_PUSHDATA1";
    case OP_PUSHDATA2              : return "OP_PUSHDATA2";
    case OP_PUSHDATA4              : return "OP_PUSHDATA4";
    case OP_1NEGATE                : return "-1";
    case OP_RESERVED               : return "OP_RESERVED";
    case OP_1                      : return "1";
    case OP_2                      : return "2";
    case OP_3                      : return "3";
    case OP_4                      : return "4";
    case OP_5                      : return "5";
    case OP_6                      : return "6";
    case OP_7                      : return "7";
    case OP_8                      : return "8";
    case OP_9                      : return "9";
    case OP_10                     : return "10";
    case OP_11                     : return "11";
    case OP_12                     : return "12";
    case OP_13                     : return "13";
    case OP_14                     : return "14";
    case OP_15                     : return "15";
    case OP_16                     : return "16";

    // control
    case OP_NOP                    : return "OP_NOP";
    case OP_VER                    : return "OP_VER";
    case OP_IF                     : return "OP_IF";
    case OP_NOTIF                  : return "OP_NOTIF";
    case OP_VERIF                  : return "OP_VERIF";
    case OP_VERNOTIF               : return "OP_VERNOTIF";
    case OP_ELSE                   : return "OP_ELSE";
    case OP_ENDIF                  : return "OP_ENDIF";
    case OP_VERIFY                 : return "OP_VERIFY";
    case OP_RETURN                 : return "OP_RETURN";

    // stack ops
    case OP_TOALTSTACK             : return "OP_TOALTSTACK";
    case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
    case OP_2DROP                  : return "OP_2DROP";
    case OP_2DUP                   : return "OP_2DUP";
    case OP_3DUP                   : return "OP_3DUP";
    case OP_2OVER                  : return "OP_2OVER";
    case OP_2ROT                   : return "OP_2ROT";
    case OP_2SWAP                  : return "OP_2SWAP";
    case OP_IFDUP                  : return "OP_IFDUP";
    case OP_DEPTH                  : return "OP_DEPTH";
    case OP_DROP                   : return "OP_DROP";
    case OP_DUP                    : return "OP_DUP";
    case OP_NIP                    : return "OP_NIP";
    case OP_OVER                   : return "OP_OVER";
    case OP_PICK                   : return "OP_PICK";
    case OP_ROLL                   : return "OP_ROLL";
    case OP_ROT                    : return "OP_ROT";
    case OP_SWAP                   : return "OP_SWAP";
    case OP_TUCK                   : return "OP_TUCK";

    // splice ops
    case OP_CAT                    : return "OP_CAT";
    case OP_SUBSTR                 : return "OP_SUBSTR";
    case OP_LEFT                   : return "OP_LEFT";
    case OP_RIGHT                  : return "OP_RIGHT";
    case OP_SIZE                   : return "OP_SIZE";

    // bit logic
    case OP_INVERT                 : return "OP_INVERT";
    case OP_AND                    : return "OP_AND";
    case OP_OR                     : return "OP_OR";
    case OP_XOR                    : return "OP_XOR";
    case OP_EQUAL                  : return "OP_EQUAL";
    case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
    case OP_RESERVED1              : return "OP_RESERVED1";
    case OP_RESERVED2              : return "OP_RESERVED2";

    // numeric
    case OP_1ADD                   : return "OP_1ADD";
    case OP_1SUB                   : return "OP_1SUB";
    case OP_2MUL                   : return "OP_2MUL";
    case OP_2DIV                   : return "OP_2DIV";
    case OP_NEGATE                 : return "OP_NEGATE";
    case OP_ABS                    : return "OP_ABS";
    case OP_NOT                    : return "OP_NOT";
    case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
    case OP_ADD                    : return "OP_ADD";
    case OP_SUB                    : return "OP_SUB";
    case OP_MUL                    : return "OP_MUL";
    case OP_DIV                    : return "OP_DIV";
    case OP_MOD                    : return "OP_MOD";
    case OP_LSHIFT                 : return "OP_LSHIFT";
    case OP_RSHIFT                 : return "OP_RSHIFT";
    case OP_BOOLAND                : return "OP_BOOLAND";
    case OP_BOOLOR                 : return "OP_BOOLOR";
    case OP_NUMEQUAL               : return "OP_NUMEQUAL";
    case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
    case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
    case OP_LESSTHAN               : return "OP_LESSTHAN";
    case OP_GREATERTHAN            : return "OP_GREATERTHAN";
    case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
    case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
    case OP_MIN                    : return "OP_MIN";
    case OP_MAX                    : return "OP_MAX";
    case OP_WITHIN                 : return "OP_WITHIN";

    // crypto
    case OP_RIPEMD160              : return "OP_RIPEMD160";
    case OP_SHA1                   : return "OP_SHA1";
    case OP_SHA256                 : return "OP_SHA256";
    case OP_HASH160                : return "OP_HASH160";
    case OP_HASH256                : return "OP_HASH256";
    case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
    case OP_CHECKSIG               : return "OP_CHECKSIG";
    case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
    case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
    case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";

    // expanson
    case OP_NOP1                   : return "OP_NOP1";
    case OP_CHECKLOCKTIMEVERIFY    : return "OP_CHECKLOCKTIMEVERIFY";
    case OP_NOP3                   : return "OP_NOP3";
    case OP_NOP4                   : return "OP_NOP4";
    case OP_NOP5                   : return "OP_NOP5";
    case OP_NOP6                   : return "OP_NOP6";
    case OP_NOP7                   : return "OP_NOP7";
    case OP_NOP8                   : return "OP_NOP8";
    case OP_NOP9                   : return "OP_NOP9";
    case OP_NOP10                  : return "OP_NOP10";

    //QSAFE Functions
    case OP_LAMPORTSIG       : return "OP_LAMPORTSIG";
    case OP_LAMPORTSIGVERIFY : return "OP_LAMPORTSIGVERIFY";

    case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";

    // Note:
    //  The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
    //  as kind of implementation hack, they are *NOT* real opcodes.  If found in real
    //  Script, just let the default: case deal with them.

    default:
        return "OP_UNKNOWN";
    }
}

unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
    unsigned int n = 0;
    const_iterator pc = begin();
    opcodetype lastOpcode = OP_INVALIDOPCODE;
    while (pc < end())
    {
        opcodetype opcode;
        if (!GetOp(pc, opcode))
            break;
        if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
            n++;
        else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
        {
            if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
                n += DecodeOP_N(lastOpcode);
            else
                n += MAX_PUBKEYS_PER_MULTISIG;
        }
        lastOpcode = opcode;
    }
    return n;
}

unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
{
    if (!IsPayToScriptHash())
        return GetSigOpCount(true);

    // This is a pay-to-script-hash scriptPubKey;
    // get the last item that the scriptSig
    // pushes onto the stack:
    const_iterator pc = scriptSig.begin();
    vector<unsigned char> data;
    while (pc < scriptSig.end())
    {
        opcodetype opcode;
        if (!scriptSig.GetOp(pc, opcode, data))
            return 0;
        if (opcode > OP_16)
            return 0;
    }

    /// ... and return its opcount:
    CScript subscript(data.begin(), data.end());
    return subscript.GetSigOpCount(true);
}

bool CScript::IsPayToScriptHash() const
{
    // Extra-fast test for pay-to-script-hash CScripts:
    return (this->size() == 23 &&
            (*this)[0] == OP_HASH160 &&
            (*this)[1] == 0x14 &&
            (*this)[22] == OP_EQUAL);
}

bool CScript::IsPushOnly(const_iterator pc) const
{
    while (pc < end())
    {
        opcodetype opcode;
        if (!GetOp(pc, opcode))
            return false;
        // Note that IsPushOnly() *does* consider OP_RESERVED to be a
        // push-type opcode, however execution of OP_RESERVED fails, so
        // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
        // the P2SH special validation code being executed.
        if (opcode > OP_16)
            return false;
    }
    return true;
}

bool CScript::IsPushOnly() const
{
    return this->IsPushOnly(begin());
}
<commit_msg>Update script.cpp<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script.h"

#include "tinyformat.h"
#include "utilstrencodings.h"

using namespace std;

const char* GetOpName(opcodetype opcode)
{
    switch (opcode)
    {
    // push value
    case OP_0                      : return "0";
    case OP_PUSHDATA1              : return "OP_PUSHDATA1";
    case OP_PUSHDATA2              : return "OP_PUSHDATA2";
    case OP_PUSHDATA4              : return "OP_PUSHDATA4";
    case OP_1NEGATE                : return "-1";
    case OP_RESERVED               : return "OP_RESERVED";
    case OP_1                      : return "1";
    case OP_2                      : return "2";
    case OP_3                      : return "3";
    case OP_4                      : return "4";
    case OP_5                      : return "5";
    case OP_6                      : return "6";
    case OP_7                      : return "7";
    case OP_8                      : return "8";
    case OP_9                      : return "9";
    case OP_10                     : return "10";
    case OP_11                     : return "11";
    case OP_12                     : return "12";
    case OP_13                     : return "13";
    case OP_14                     : return "14";
    case OP_15                     : return "15";
    case OP_16                     : return "16";

    // control
    case OP_NOP                    : return "OP_NOP";
    case OP_VER                    : return "OP_VER";
    case OP_IF                     : return "OP_IF";
    case OP_NOTIF                  : return "OP_NOTIF";
    case OP_VERIF                  : return "OP_VERIF";
    case OP_VERNOTIF               : return "OP_VERNOTIF";
    case OP_ELSE                   : return "OP_ELSE";
    case OP_ENDIF                  : return "OP_ENDIF";
    case OP_VERIFY                 : return "OP_VERIFY";
    case OP_RETURN                 : return "OP_RETURN";

    // stack ops
    case OP_TOALTSTACK             : return "OP_TOALTSTACK";
    case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
    case OP_2DROP                  : return "OP_2DROP";
    case OP_2DUP                   : return "OP_2DUP";
    case OP_3DUP                   : return "OP_3DUP";
    case OP_2OVER                  : return "OP_2OVER";
    case OP_2ROT                   : return "OP_2ROT";
    case OP_2SWAP                  : return "OP_2SWAP";
    case OP_IFDUP                  : return "OP_IFDUP";
    case OP_DEPTH                  : return "OP_DEPTH";
    case OP_DROP                   : return "OP_DROP";
    case OP_DUP                    : return "OP_DUP";
    case OP_NIP                    : return "OP_NIP";
    case OP_OVER                   : return "OP_OVER";
    case OP_PICK                   : return "OP_PICK";
    case OP_ROLL                   : return "OP_ROLL";
    case OP_ROT                    : return "OP_ROT";
    case OP_SWAP                   : return "OP_SWAP";
    case OP_TUCK                   : return "OP_TUCK";

    // splice ops
    case OP_CAT                    : return "OP_CAT";
    case OP_SUBSTR                 : return "OP_SUBSTR";
    case OP_LEFT                   : return "OP_LEFT";
    case OP_RIGHT                  : return "OP_RIGHT";
    case OP_SIZE                   : return "OP_SIZE";

    // bit logic
    case OP_INVERT                 : return "OP_INVERT";
    case OP_AND                    : return "OP_AND";
    case OP_OR                     : return "OP_OR";
    case OP_XOR                    : return "OP_XOR";
    case OP_EQUAL                  : return "OP_EQUAL";
    case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
    case OP_RESERVED1              : return "OP_RESERVED1";
    case OP_RESERVED2              : return "OP_RESERVED2";

    // numeric
    case OP_1ADD                   : return "OP_1ADD";
    case OP_1SUB                   : return "OP_1SUB";
    case OP_2MUL                   : return "OP_2MUL";
    case OP_2DIV                   : return "OP_2DIV";
    case OP_NEGATE                 : return "OP_NEGATE";
    case OP_ABS                    : return "OP_ABS";
    case OP_NOT                    : return "OP_NOT";
    case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
    case OP_ADD                    : return "OP_ADD";
    case OP_SUB                    : return "OP_SUB";
    case OP_MUL                    : return "OP_MUL";
    case OP_DIV                    : return "OP_DIV";
    case OP_MOD                    : return "OP_MOD";
    case OP_LSHIFT                 : return "OP_LSHIFT";
    case OP_RSHIFT                 : return "OP_RSHIFT";
    case OP_BOOLAND                : return "OP_BOOLAND";
    case OP_BOOLOR                 : return "OP_BOOLOR";
    case OP_NUMEQUAL               : return "OP_NUMEQUAL";
    case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
    case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
    case OP_LESSTHAN               : return "OP_LESSTHAN";
    case OP_GREATERTHAN            : return "OP_GREATERTHAN";
    case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
    case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
    case OP_MIN                    : return "OP_MIN";
    case OP_MAX                    : return "OP_MAX";
    case OP_WITHIN                 : return "OP_WITHIN";

    // crypto
    case OP_RIPEMD160              : return "OP_RIPEMD160";
    case OP_SHA1                   : return "OP_SHA1";
    case OP_SHA256                 : return "OP_SHA256";
    case OP_HASH160                : return "OP_HASH160";
    case OP_HASH256                : return "OP_HASH256";
    case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
    case OP_CHECKSIG               : return "OP_CHECKSIG";
    case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
    case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
    case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";

    // expanson
    case OP_NOP1                   : return "OP_NOP1";
    case OP_CHECKLOCKTIMEVERIFY    : return "OP_CHECKLOCKTIMEVERIFY";
    case OP_NOP3                   : return "OP_NOP3";
    case OP_NOP4                   : return "OP_NOP4";
    case OP_NOP5                   : return "OP_NOP5";
    case OP_NOP6                   : return "OP_NOP6";
    case OP_NOP7                   : return "OP_NOP7";
    case OP_NOP8                   : return "OP_NOP8";
    case OP_NOP9                   : return "OP_NOP9";
    case OP_NOP10                  : return "OP_NOP10";

    //QSAFE Functions
    case OP_LAMPORTCHECKSIG       : return "OP_LAMPORTSIG";
    case OP_LAMPORTCHECKSIGVERIFY : return "OP_LAMPORTSIGVERIFY";

    case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";

    // Note:
    //  The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
    //  as kind of implementation hack, they are *NOT* real opcodes.  If found in real
    //  Script, just let the default: case deal with them.

    default:
        return "OP_UNKNOWN";
    }
}

unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
    unsigned int n = 0;
    const_iterator pc = begin();
    opcodetype lastOpcode = OP_INVALIDOPCODE;
    while (pc < end())
    {
        opcodetype opcode;
        if (!GetOp(pc, opcode))
            break;
        if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
            n++;
        else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
        {
            if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
                n += DecodeOP_N(lastOpcode);
            else
                n += MAX_PUBKEYS_PER_MULTISIG;
        }
        lastOpcode = opcode;
    }
    return n;
}

unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
{
    if (!IsPayToScriptHash())
        return GetSigOpCount(true);

    // This is a pay-to-script-hash scriptPubKey;
    // get the last item that the scriptSig
    // pushes onto the stack:
    const_iterator pc = scriptSig.begin();
    vector<unsigned char> data;
    while (pc < scriptSig.end())
    {
        opcodetype opcode;
        if (!scriptSig.GetOp(pc, opcode, data))
            return 0;
        if (opcode > OP_16)
            return 0;
    }

    /// ... and return its opcount:
    CScript subscript(data.begin(), data.end());
    return subscript.GetSigOpCount(true);
}

bool CScript::IsPayToScriptHash() const
{
    // Extra-fast test for pay-to-script-hash CScripts:
    return (this->size() == 23 &&
            (*this)[0] == OP_HASH160 &&
            (*this)[1] == 0x14 &&
            (*this)[22] == OP_EQUAL);
}

bool CScript::IsPushOnly(const_iterator pc) const
{
    while (pc < end())
    {
        opcodetype opcode;
        if (!GetOp(pc, opcode))
            return false;
        // Note that IsPushOnly() *does* consider OP_RESERVED to be a
        // push-type opcode, however execution of OP_RESERVED fails, so
        // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
        // the P2SH special validation code being executed.
        if (opcode > OP_16)
            return false;
    }
    return true;
}

bool CScript::IsPushOnly() const
{
    return this->IsPushOnly(begin());
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	線形代数的数学ユーティリティー（ヘッダー）
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/glfw_app/blob/master/LICENSE
*/
//=====================================================================//
#include "utils/vtx.hpp"

namespace vtx {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	配置型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	struct placement {
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	水平配置型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct holizontal {
			enum type {
				NONE,		///< 無効果
				LEFT,		///< 左
				CENTER,		///< 中央
				RIGHT,		///< 右
			};
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	垂直配置型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct vertical {
			enum type {
				NONE,		///< 無効果
				TOP,		///< 上
				CENTER,		///< 中央
				BOTTOM,		///< 下
			};
		};

		holizontal::type	hpt;
		vertical::type		vpt;
		placement(holizontal::type hpt_ = holizontal::NONE,
				  vertical::type vpt_ = vertical::NONE) : hpt(hpt_), vpt(vpt_) { }
	};

	//-----------------------------------------------------------------//
	/*!
		@brief	配置を作成
		@param[in]	area	エリア
		@param[in]	size	配置サイズ
		@param[in]	pt		配置型
		@param[out]	dst		位置
	*/
	//-----------------------------------------------------------------//
	template <typename T>
	void create_placement(const rectangle<T>& area, const vertex2<T>& size,
		const placement& pt, vertex2<T>& dst)
	{
		if(pt.hpt == placement::holizontal::LEFT) {
			dst.x = area.org.x;
		} else if(pt.hpt == placement::holizontal::CENTER) {
			dst.x = area.org.x + (area.size.x - size.x) / 2;
		} else if(pt.hpt == placement::holizontal::RIGHT) {
			dst.x = area.end_x() - size.x;
		}

		if(pt.vpt == placement::vertical::TOP) {
			dst.y = area.org.y;
		} else if(pt.vpt == placement::vertical::CENTER) {
			dst.y = area.org.y + (area.size.y - size.y) / 2;
		} else if(pt.vpt == placement::vertical::BOTTOM) {
			dst.y = area.end_y() - size.y;
		}
	}

#if 0
	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定
		@param[in]	p	直線座標ｐ
		@param[in]	q	直線座標q
		@param[in]	v	三角の座標列
		@param[out]	cp	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool line_hit_triangle(const fvtx& p, const fvtx& q, const fvtx v[3], fvtx& cp);
#endif

	//-----------------------------------------------------------------//
	/*!
		@brief	三角形内に点が存在するか（二次元空間）
		@param[in]	pos	点の座標
		@param[in]	v0	三角の座標 0
		@param[in]	v1	三角の座標 1
		@param[in]	v2	三角の座標 2
		@return あれば「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_in_point(const fpos& pos, const fvtx& v0, const fvtx& v1, const fvtx& v2);

	//-----------------------------------------------------------------//
	/*!
		@brief	多角形内に点が存在するか
		@param[in]	pos	点の座標
		@param[in]	src	頂点の座標列
		@return あれば「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool polygon_in_point(const fpos& pos, const fposs& src);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[in]	tv	三角の座標列
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_intersect(const fvtx& org, const fvtx& dir, const fvtx tv[3], fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定２（有限直線）
		@param[in]	org	直線起点
		@param[in]	end	直線方向
		@param[in]	tv	三角の座標列
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_intersect2(const fvtx& org, const fvtx& end, const fvtx tv[3], fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と四角形の当たり判定
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[in]	vlist	時計周り頂点リスト
		@param[out]	crs	交点座標
		@return 当たりなら四角形内三角形の番号 (1: 0-1-2, 2: 2-3-0)
	*/
	//-----------------------------------------------------------------//
	int quadrangle_intersect(const fvtx& org, const fvtx& dir, const fvtxs& vlist, fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と四角形の当たり判定その２（有限直線）
		@param[in]	org	直線起点
		@param[in]	end	直線終点
		@param[in]	vlist	時計周り頂点リスト
		@param[out]	crs	交点座標
		@return 当たりなら四角形内三角形の番号 (1: 0-1-2, 2: 2-3-0)
	*/
	//-----------------------------------------------------------------//
	int quadrangle_intersect2(const fvtx& org, const fvtx& end, const fvtxs& vlist, fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と球の当たり判定
		@param[in]	r	球の半径
		@param[in]	cen	球の中心
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool sphere_line_collision(float r, const fvtx& cen, const fvtx& org, const fvtx dir, fvtx& crs);

	void surface_ratio(const fpos& scr, const fvtxs& suf, const fvtxs& in, fvtx& out);

}	// namespace vtx

<commit_msg>cleanup enum class<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	線形代数的数学ユーティリティー（ヘッダー）
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/glfw_app/blob/master/LICENSE
*/
//=====================================================================//
#include "utils/vtx.hpp"

namespace vtx {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	配置型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	struct placement {

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	水平配置型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class holizontal {
			NONE,		///< 無効果
			LEFT,		///< 左
			CENTER,		///< 中央
			RIGHT,		///< 右
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	垂直配置型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class vertical {
			NONE,		///< 無効果
			TOP,		///< 上
			CENTER,		///< 中央
			BOTTOM,		///< 下
		};

		holizontal	hpt;
		vertical	vpt;
		placement(holizontal hpt_ = holizontal::NONE, vertical vpt_ = vertical::NONE) : hpt(hpt_), vpt(vpt_) { }
	};

	//-----------------------------------------------------------------//
	/*!
		@brief	配置を作成
		@param[in]	area	エリア
		@param[in]	size	配置サイズ
		@param[in]	pt		配置型
		@param[out]	dst		位置
	*/
	//-----------------------------------------------------------------//
	template <typename T>
	void create_placement(const rectangle<T>& area, const vertex2<T>& size,
		const placement& pt, vertex2<T>& dst)
	{
		if(pt.hpt == placement::holizontal::LEFT) {
			dst.x = area.org.x;
		} else if(pt.hpt == placement::holizontal::CENTER) {
			dst.x = area.org.x + (area.size.x - size.x) / 2;
		} else if(pt.hpt == placement::holizontal::RIGHT) {
			dst.x = area.end_x() - size.x;
		}

		if(pt.vpt == placement::vertical::TOP) {
			dst.y = area.org.y;
		} else if(pt.vpt == placement::vertical::CENTER) {
			dst.y = area.org.y + (area.size.y - size.y) / 2;
		} else if(pt.vpt == placement::vertical::BOTTOM) {
			dst.y = area.end_y() - size.y;
		}
	}

#if 0
	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定
		@param[in]	p	直線座標ｐ
		@param[in]	q	直線座標q
		@param[in]	v	三角の座標列
		@param[out]	cp	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool line_hit_triangle(const fvtx& p, const fvtx& q, const fvtx v[3], fvtx& cp);
#endif

	//-----------------------------------------------------------------//
	/*!
		@brief	三角形内に点が存在するか（二次元空間）
		@param[in]	pos	点の座標
		@param[in]	v0	三角の座標 0
		@param[in]	v1	三角の座標 1
		@param[in]	v2	三角の座標 2
		@return あれば「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_in_point(const fpos& pos, const fvtx& v0, const fvtx& v1, const fvtx& v2);

	//-----------------------------------------------------------------//
	/*!
		@brief	多角形内に点が存在するか
		@param[in]	pos	点の座標
		@param[in]	src	頂点の座標列
		@return あれば「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool polygon_in_point(const fpos& pos, const fposs& src);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[in]	tv	三角の座標列
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_intersect(const fvtx& org, const fvtx& dir, const fvtx tv[3], fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と三角の当たり判定２（有限直線）
		@param[in]	org	直線起点
		@param[in]	end	直線方向
		@param[in]	tv	三角の座標列
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool triangle_intersect2(const fvtx& org, const fvtx& end, const fvtx tv[3], fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と四角形の当たり判定
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[in]	vlist	時計周り頂点リスト
		@param[out]	crs	交点座標
		@return 当たりなら四角形内三角形の番号 (1: 0-1-2, 2: 2-3-0)
	*/
	//-----------------------------------------------------------------//
	int quadrangle_intersect(const fvtx& org, const fvtx& dir, const fvtxs& vlist, fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と四角形の当たり判定その２（有限直線）
		@param[in]	org	直線起点
		@param[in]	end	直線終点
		@param[in]	vlist	時計周り頂点リスト
		@param[out]	crs	交点座標
		@return 当たりなら四角形内三角形の番号 (1: 0-1-2, 2: 2-3-0)
	*/
	//-----------------------------------------------------------------//
	int quadrangle_intersect2(const fvtx& org, const fvtx& end, const fvtxs& vlist, fvtx& crs);

	//-----------------------------------------------------------------//
	/*!
		@brief	直線と球の当たり判定
		@param[in]	r	球の半径
		@param[in]	cen	球の中心
		@param[in]	org	直線起点
		@param[in]	dir	直線方向
		@param[out]	crs	交点座標
		@return 当たりなら「true」を返す
	*/
	//-----------------------------------------------------------------//
	bool sphere_line_collision(float r, const fvtx& cen, const fvtx& org, const fvtx dir, fvtx& crs);

	void surface_ratio(const fpos& scr, const fvtxs& suf, const fvtxs& in, fvtx& out);

}	// namespace vtx

<|endoftext|>


<commit_before>//
// Copyright (C) Zbigniew Zagorski <z.zagorski@gmail.com>,
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details
// I.e., do what you like, but keep copyright and there's NO WARRANTY.
//

#include <ostream>
#include <iostream>
#include <iomanip>
#include <string.h>

#include "tinfra/fmt.h"
#include "tinfra/runtime.h"

namespace tinfra {

void print_stacktrace(stacktrace_t const& st, std::ostream& out)
{

    for( stacktrace_t::const_iterator i = st.begin(); i != st.end(); ++i ) {
        void* address = *i;
        debug_info di;
        out << "\tat ";
        if( get_debug_info(address, di) ) {
            // func(file:line)
            out << di.function;
            if( di.source_file.size() > 0 ) {
                out << "(" << di.source_file;
                if( di.source_line != 0 )
                    out << ":" << std::dec << di.source_line;
                out << ")";
            }
        }
        //  0xabcdef123
        out << "[" << std::setfill('0') << std::setw(sizeof(address)) << std::hex << address << "]";
        out << std::endl;
    }
}

void (*fatal_exception_handler) (void) = 0;

void set_fatal_exception_handler(void (*handler) (void))
{
    fatal_exception_handler = handler;
}

// initialize platform specific fatal error
// handling
void initialize_platform_runtime();
void terminate_handler();

void initialize_fatal_exception_handler()
{
    static bool initialized = false;
    if( initialized )
        return;

    initialize_platform_runtime();

    std::set_terminate(terminate_handler);
}

void terminate_handler()
{
    fatal_exit("terminate called");
}

void fatal_exit(const char* message, stacktrace_t& stacktrace)
{
    if( fatal_exception_handler ) {
	fatal_exception_handler();
    }
    std::cerr << get_exepath() << ": " << message << std::endl;
    if( stacktrace.size() > 0 )
        print_stacktrace(stacktrace, std::cerr);
    std::cerr << "aborting" << std::endl;
    abort();
}

void fatal_exit(const char* message)
{
    stacktrace_t stacktrace;
    if( is_stacktrace_supported() ) {
        get_stacktrace(stacktrace);
    }

    fatal_exit(message, stacktrace);
}

void interrupt_exit(const char* message)
{
    std::cerr << get_exepath() << ": " << message << std::endl;
    exit(1);
}

interrupted_exception::interrupted_exception()
    : std::runtime_error("interrupted")
{}

interrupt_policy current_interrupt_policy = IMMEDIATE_ABORT;
bool interrupted = false;

void interrupt()
{
    if( current_interrupt_policy == IMMEDIATE_ABORT ) {
        interrupt_exit("interrupted");
    } else {
        interrupted = true;
    }
}

void test_interrupt()
{
    if( interrupted )
        throw interrupted_exception();
}

void set_interrupt_policy(interrupt_policy p)
{
    current_interrupt_policy = p;
}

} // end of namespace tinfra

<commit_msg>use sigatomic_t var for storing interrupted flag<commit_after>//
// Copyright (C) Zbigniew Zagorski <z.zagorski@gmail.com>,
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details
// I.e., do what you like, but keep copyright and there's NO WARRANTY.
//

#include <ostream>
#include <iostream>
#include <iomanip>
#include <string.h>

#include "tinfra/fmt.h"
#include "tinfra/runtime.h"

#if 0 // TODO woe32 part of this
#include <csignal>
using std::sigatomic_t;
#else
typedef int sigatomic_t;
#endif

namespace tinfra {

void print_stacktrace(stacktrace_t const& st, std::ostream& out)
{

    for( stacktrace_t::const_iterator i = st.begin(); i != st.end(); ++i ) {
        void* address = *i;
        debug_info di;
        out << "\tat ";
        if( get_debug_info(address, di) ) {
            // func(file:line)
            out << di.function;
            if( di.source_file.size() > 0 ) {
                out << "(" << di.source_file;
                if( di.source_line != 0 )
                    out << ":" << std::dec << di.source_line;
                out << ")";
            }
        }
        //  0xabcdef123
        out << "[" << std::setfill('0') << std::setw(sizeof(address)) << std::hex << address << "]";
        out << std::endl;
    }
}

void (*fatal_exception_handler) (void) = 0;

void set_fatal_exception_handler(void (*handler) (void))
{
    fatal_exception_handler = handler;
}

// initialize platform specific fatal error
// handling
void initialize_platform_runtime();
void terminate_handler();

void initialize_fatal_exception_handler()
{
    static bool initialized = false;
    if( initialized )
        return;

    initialize_platform_runtime();

    std::set_terminate(terminate_handler);
}

void terminate_handler()
{
    fatal_exit("terminate called");
}

void fatal_exit(const char* message, stacktrace_t& stacktrace)
{
    if( fatal_exception_handler ) {
	fatal_exception_handler();
    }
    std::cerr << get_exepath() << ": " << message << std::endl;
    if( stacktrace.size() > 0 )
        print_stacktrace(stacktrace, std::cerr);
    std::cerr << "aborting" << std::endl;
    abort();
}

void fatal_exit(const char* message)
{
    stacktrace_t stacktrace;
    if( is_stacktrace_supported() ) {
        get_stacktrace(stacktrace);
    }

    fatal_exit(message, stacktrace);
}

//
// *interrupt* here is about high level user interrupt
// it's not about interrupt by ANY signal it's about
// interrupt caused by closing program or reqursting termination
// by Ctrl+C, Ctrl+Break, SIGINT, SIGTERN
//
void interrupt_exit(const char* message)
{
    std::cerr << get_exepath() << ": " << message << std::endl;
    exit(1);
}

interrupted_exception::interrupted_exception()
    : std::runtime_error("interrupted")
{}

// TODO:    interrupt should be thread local somehow
         // ???
interrupt_policy current_interrupt_policy = IMMEDIATE_ABORT;
static volatile sigatomic_t interrupted = 0;

void interrupt()
{
    if( current_interrupt_policy == IMMEDIATE_ABORT ) {
        interrupt_exit("interrupted");
    } else {
        interrupted = 1;
    }
}

void test_interrupt()
{
    if( interrupted ) {
        interrupted = 0;
        throw interrupted_exception();
    }
}

void set_interrupt_policy(interrupt_policy p)
{
    current_interrupt_policy = p;
}

} // end of namespace tinfra

<|endoftext|>


<commit_before>/**
 * \file
 * \brief OperationCountingType class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-15
 */

#ifndef TEST_OPERATIONCOUNTINGTYPE_HPP_
#define TEST_OPERATIONCOUNTINGTYPE_HPP_

#include <utility>

#include <cstddef>

namespace distortos
{

namespace test
{

/// OperationCountingType class counts important operations (construction, destruction, assignment, swap) in static
/// variables; counting is not thread-safe!
class OperationCountingType
{
public:

	/**
	 * \brief OperationCountingType's constructor
	 *
	 * \param [in] value is the value held by object, default - zero
	 */

	explicit OperationCountingType(const unsigned int value = {}) :
			value_{value}
	{
		++constructed_;
	}

	/**
	 * \brief OperationCountingType's copy constructor
	 *
	 * \param [in] other is a reference to OperationCountingType object used as source of copy
	 */

	OperationCountingType(const OperationCountingType& other) :
			value_{other.value_}
	{
		++copyConstructed_;
	}

	/**
	 * \brief OperationCountingType's move constructor
	 *
	 * \param [in] other is a rvalue reference to OperationCountingType object used as source of move
	 */

	OperationCountingType(OperationCountingType&& other) :
			value_{other.value_}
	{
		other.value_ = {};
		++moveConstructed_;
	}

	/**
	 * \brief OperationCountingType's destructor
	 */

	~OperationCountingType()
	{
		value_ = {};
		++destructed_;
	}

	/**
	 * \brief OperationCountingType's copy assignment
	 *
	 * \param [in] other is a reference to OperationCountingType object used as source of copy assignment
	 *
	 * \return reference to this
	 */

	OperationCountingType& operator=(const OperationCountingType& other)
	{
		value_ = other.value_;
		++copyAssigned_;
		return *this;
	}

	/**
	 * \brief OperationCountingType's move assignment
	 *
	 * \param [in] other is a rvalue reference to OperationCountingType object used as source of move assignment
	 *
	 * \return reference to this
	 */

	OperationCountingType& operator=(OperationCountingType&& other)
	{
		value_ = other.value_;
		other.value_ = {};
		++moveAssigned_;
		return *this;
	}

	/**
	 * \brief OperationCountingType's swap overload
	 *
	 * \param [in] left is a reference to first OperationCountingType object
	 * \param [in] right is a reference to second OperationCountingType object
	 */

	friend void swap(OperationCountingType& left, OperationCountingType& right)
	{
		using std::swap;
		swap(left.value_, right.value_);
		++swapped_;
	}

	/**
	 * \brief Equality comparison operator for OperationCountingType
	 *
	 * \param [in] left is a reference to left operand of equality comparison
	 * \param [in] right is a reference to right operand of equality comparison
	 *
	 * \return true if operands are equal, false otherwise
	 */

	friend bool operator==(const OperationCountingType& left, const OperationCountingType& right)
	{
		return left.value_ == right.value_;
	}

	/**
	 * \brief Checks value of counters.
	 *
	 * \param [in] constructed is expected number of constructor calls since last resetCounters() call
	 * \param [in] copyConstructed is expected number of copy constructor calls since last resetCounters() call
	 * \param [in] moveConstructed is expected number of move constructor calls since last resetCounters() call
	 * \param [in] destructed is expected number of destructor calls since last resetCounters() call
	 * \param [in] copyAssigned is expected number of copy assignment calls since last resetCounters() call
	 * \param [in] moveAssigned is expected number of move assignment calls since last resetCounters() call
	 * \param [in] swapped is expected number of swap calls since last resetCounters() call
	 *
	 * \return true if counters match expected values, false otherwise
	 */

	static bool checkCounters(size_t constructed, size_t copyConstructed, size_t moveConstructed, size_t destructed,
			size_t copyAssigned, size_t moveAssigned, size_t swapped);

	/**
	 * \brief Resets value of all counters.
	 */

	static void resetCounters();

private:

	/// value held by object
	unsigned int value_;

	/// counter of constructor calls since last resetCounters() call
	static size_t constructed_;

	/// counter of copy constructor calls since last resetCounters() call
	static size_t copyConstructed_;

	/// counter of move constructor calls since last resetCounters() call
	static size_t moveConstructed_;

	/// counter of destructor calls since last resetCounters() call
	static size_t destructed_;

	/// counter of copy assignment calls since last resetCounters() call
	static size_t copyAssigned_;

	/// counter of move assignment calls since last resetCounters() call
	static size_t moveAssigned_;

	/// counter of swap calls since last resetCounters() call
	static size_t swapped_;
};

/**
 * \brief Inequality comparison operator for OperationCountingType
 *
 * \param [in] left is a reference to left operand of inequality comparison
 * \param [in] right is a reference to right operand of inequality comparison
 *
 * \return true if operands are not equal, false otherwise
 */

inline bool operator!=(const OperationCountingType& left, const OperationCountingType& right)
{
	return (left == right) == false;
}

}	// namespace test

}	// namespace distortos

#endif	// TEST_OPERATIONCOUNTINGTYPE_HPP_
<commit_msg>test: add type alias for type of "value" in OperationCountingType<commit_after>/**
 * \file
 * \brief OperationCountingType class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-29
 */

#ifndef TEST_OPERATIONCOUNTINGTYPE_HPP_
#define TEST_OPERATIONCOUNTINGTYPE_HPP_

#include <utility>

#include <cstddef>

namespace distortos
{

namespace test
{

/// OperationCountingType class counts important operations (construction, destruction, assignment, swap) in static
/// variables; counting is not thread-safe!
class OperationCountingType
{
public:

	/// type used for OperationCountingType's "value"
	using Value = unsigned int;

	/**
	 * \brief OperationCountingType's constructor
	 *
	 * \param [in] value is the value held by object, default - zero
	 */

	explicit OperationCountingType(const Value value = {}) :
			value_{value}
	{
		++constructed_;
	}

	/**
	 * \brief OperationCountingType's copy constructor
	 *
	 * \param [in] other is a reference to OperationCountingType object used as source of copy
	 */

	OperationCountingType(const OperationCountingType& other) :
			value_{other.value_}
	{
		++copyConstructed_;
	}

	/**
	 * \brief OperationCountingType's move constructor
	 *
	 * \param [in] other is a rvalue reference to OperationCountingType object used as source of move
	 */

	OperationCountingType(OperationCountingType&& other) :
			value_{other.value_}
	{
		other.value_ = {};
		++moveConstructed_;
	}

	/**
	 * \brief OperationCountingType's destructor
	 */

	~OperationCountingType()
	{
		value_ = {};
		++destructed_;
	}

	/**
	 * \brief OperationCountingType's copy assignment
	 *
	 * \param [in] other is a reference to OperationCountingType object used as source of copy assignment
	 *
	 * \return reference to this
	 */

	OperationCountingType& operator=(const OperationCountingType& other)
	{
		value_ = other.value_;
		++copyAssigned_;
		return *this;
	}

	/**
	 * \brief OperationCountingType's move assignment
	 *
	 * \param [in] other is a rvalue reference to OperationCountingType object used as source of move assignment
	 *
	 * \return reference to this
	 */

	OperationCountingType& operator=(OperationCountingType&& other)
	{
		value_ = other.value_;
		other.value_ = {};
		++moveAssigned_;
		return *this;
	}

	/**
	 * \brief OperationCountingType's swap overload
	 *
	 * \param [in] left is a reference to first OperationCountingType object
	 * \param [in] right is a reference to second OperationCountingType object
	 */

	friend void swap(OperationCountingType& left, OperationCountingType& right)
	{
		using std::swap;
		swap(left.value_, right.value_);
		++swapped_;
	}

	/**
	 * \brief Equality comparison operator for OperationCountingType
	 *
	 * \param [in] left is a reference to left operand of equality comparison
	 * \param [in] right is a reference to right operand of equality comparison
	 *
	 * \return true if operands are equal, false otherwise
	 */

	friend bool operator==(const OperationCountingType& left, const OperationCountingType& right)
	{
		return left.value_ == right.value_;
	}

	/**
	 * \brief Checks value of counters.
	 *
	 * \param [in] constructed is expected number of constructor calls since last resetCounters() call
	 * \param [in] copyConstructed is expected number of copy constructor calls since last resetCounters() call
	 * \param [in] moveConstructed is expected number of move constructor calls since last resetCounters() call
	 * \param [in] destructed is expected number of destructor calls since last resetCounters() call
	 * \param [in] copyAssigned is expected number of copy assignment calls since last resetCounters() call
	 * \param [in] moveAssigned is expected number of move assignment calls since last resetCounters() call
	 * \param [in] swapped is expected number of swap calls since last resetCounters() call
	 *
	 * \return true if counters match expected values, false otherwise
	 */

	static bool checkCounters(size_t constructed, size_t copyConstructed, size_t moveConstructed, size_t destructed,
			size_t copyAssigned, size_t moveAssigned, size_t swapped);

	/**
	 * \brief Resets value of all counters.
	 */

	static void resetCounters();

private:

	/// value held by object
	Value value_;

	/// counter of constructor calls since last resetCounters() call
	static size_t constructed_;

	/// counter of copy constructor calls since last resetCounters() call
	static size_t copyConstructed_;

	/// counter of move constructor calls since last resetCounters() call
	static size_t moveConstructed_;

	/// counter of destructor calls since last resetCounters() call
	static size_t destructed_;

	/// counter of copy assignment calls since last resetCounters() call
	static size_t copyAssigned_;

	/// counter of move assignment calls since last resetCounters() call
	static size_t moveAssigned_;

	/// counter of swap calls since last resetCounters() call
	static size_t swapped_;
};

/**
 * \brief Inequality comparison operator for OperationCountingType
 *
 * \param [in] left is a reference to left operand of inequality comparison
 * \param [in] right is a reference to right operand of inequality comparison
 *
 * \return true if operands are not equal, false otherwise
 */

inline bool operator!=(const OperationCountingType& left, const OperationCountingType& right)
{
	return (left == right) == false;
}

}	// namespace test

}	// namespace distortos

#endif	// TEST_OPERATIONCOUNTINGTYPE_HPP_
<|endoftext|>


<commit_before>#include "engine/Engine.hpp"

#include <SDL2/SDL.h>

using namespace std;
using namespace glm;

Engine::Engine(int argc, char** argv) : _wnd(nullptr)
{
	for(int i = 0; i < argc; ++i)
		_args.push_back(string{argv[i]});
}

Engine::~Engine()
{ }

int Engine::run(Application* app)
{
	_running = true;
	_exit_code = 0;
	SDL_Init(SDL_INIT_VIDEO);

	SDL_DisplayMode ask_mode;
	ask_mode.format = SDL_PIXELFORMAT_RGBA8888;
	ask_mode.w = 1920;
	ask_mode.h = 1080;
	ask_mode.refresh_rate = 60;
	SDL_DisplayMode mode;
	SDL_GetClosestDisplayMode(0, &ask_mode, &mode);

	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, SDL_TRUE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
	_wnd = SDL_CreateWindow("OpenGL ES 2.0 Rendering Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.w, mode.h, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
	SDL_SetWindowDisplayMode(_wnd, &mode);
	SDL_GLContext ctx = SDL_GL_CreateContext(_wnd);
	SDL_GL_MakeCurrent(_wnd, ctx);

	gladLoadGLES2Loader((GLADloadproc) &SDL_GL_GetProcAddress);

	auto fb_size = framebuffer_size();
	glViewport(0, 0, fb_size.x, fb_size.y);
	glClearColor(0.2f, 0.2f, 0.2f, 1.f);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	SDL_GL_SetSwapInterval(1);
	SDL_GL_SwapWindow(_wnd);

	app->initialize();

	TimePoint last_time{};
	Duration accumulator{};
	while(_running)
	{
		TimePoint new_time = Clock::now();
		Duration dT = new_time - last_time;
		last_time = new_time;
		accumulator += dT;

		SDL_Event e;
		while(SDL_PollEvent(&e))
		{
			if(e.type == SDL_WINDOWEVENT_CLOSE)
				_running = false;
			if(e.type == SDL_KEYUP || e.type == SDL_KEYDOWN)
				app->keyboard_event(static_cast<Key>(e.key.keysym.scancode), e.type == SDL_KEYDOWN);
			if(e.type == SDL_TEXTINPUT)
				app->keyboard_character_event(e.text.text);
			if(e.type == SDL_MOUSEMOTION)
				app->mouse_move_event({e.motion.xrel, e.motion.yrel});
			if(e.type == SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEBUTTONDOWN)
				app->mouse_button_event({e.button.x, e.button.y}, static_cast<MouseButton>(e.button.button), e.type == SDL_MOUSEBUTTONDOWN);
			if(e.type == SDL_MOUSEWHEEL)
				app->scroll_event({e.wheel.x, e.wheel.y});
			if(e.type == SDL_WINDOWEVENT_RESIZED)
				app->resize_event(e.window.data1, e.window.data2);
		}

		if(accumulator >= app->fixed_time_step())
		{
			app->update(accumulator);
			accumulator = Duration{};
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

		app->frame_start();
		app->frame();
		app->frame_end();

		SDL_GL_SwapWindow(_wnd);
	}

	delete app;

	SDL_GL_DeleteContext(ctx);
	SDL_DestroyWindow(_wnd);
	_wnd = nullptr;

	SDL_Quit();
	return _exit_code;
}

glm::ivec2 Engine::framebuffer_size() const
{
	ivec2 ret;
	SDL_GL_GetDrawableSize(_wnd, &ret.x, &ret.y);
	return ret;
}

glm::ivec2 Engine::window_size() const
{
	ivec2 ret;
	SDL_GetWindowSize(_wnd, &ret.x, &ret.y);
	return ret;
}
<commit_msg>Added some output about the OpenGL Driver (vendor, version, etc)<commit_after>#include "engine/Engine.hpp"

#include <SDL2/SDL.h>
#include <iostream>

using namespace std;
using namespace glm;

Engine::Engine(int argc, char** argv) : _wnd(nullptr)
{
	for(int i = 0; i < argc; ++i)
		_args.push_back(string{argv[i]});
}

Engine::~Engine()
{ }

int Engine::run(Application* app)
{
	_running = true;
	_exit_code = 0;
	SDL_Init(SDL_INIT_VIDEO);

	SDL_DisplayMode ask_mode;
	ask_mode.format = SDL_PIXELFORMAT_RGBA8888;
	ask_mode.w = 1920;
	ask_mode.h = 1080;
	ask_mode.refresh_rate = 60;
	SDL_DisplayMode mode;
	SDL_GetClosestDisplayMode(0, &ask_mode, &mode);

	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, SDL_TRUE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
	_wnd = SDL_CreateWindow("OpenGL ES 2.0 Rendering Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.w, mode.h, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
	SDL_SetWindowDisplayMode(_wnd, &mode);
	SDL_GLContext ctx = SDL_GL_CreateContext(_wnd);
	SDL_GL_MakeCurrent(_wnd, ctx);

	gladLoadGLES2Loader((GLADloadproc) &SDL_GL_GetProcAddress);

	auto fb_size = framebuffer_size();
	glViewport(0, 0, fb_size.x, fb_size.y);
	glClearColor(0.2f, 0.2f, 0.2f, 1.f);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	SDL_GL_SetSwapInterval(1);
	SDL_GL_SwapWindow(_wnd);

	cout << "<=-- OpenGL Info --=>" << endl
		 << " Renderer : " << glGetString(GL_RENDERER) << endl
		 << " Version : " << glGetString(GL_VERSION) << endl
		 << " Vendor : " << glGetString(GL_VENDOR) << endl
		 << " GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl << endl;

	app->initialize();

	TimePoint last_time{};
	Duration accumulator{};
	while(_running)
	{
		TimePoint new_time = Clock::now();
		Duration dT = new_time - last_time;
		last_time = new_time;
		accumulator += dT;

		SDL_Event e;
		while(SDL_PollEvent(&e))
		{
			if(e.type == SDL_WINDOWEVENT_CLOSE)
				_running = false;
			if(e.type == SDL_KEYUP || e.type == SDL_KEYDOWN)
				app->keyboard_event(static_cast<Key>(e.key.keysym.scancode), e.type == SDL_KEYDOWN);
			if(e.type == SDL_TEXTINPUT)
				app->keyboard_character_event(e.text.text);
			if(e.type == SDL_MOUSEMOTION)
				app->mouse_move_event({e.motion.xrel, e.motion.yrel});
			if(e.type == SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEBUTTONDOWN)
				app->mouse_button_event({e.button.x, e.button.y}, static_cast<MouseButton>(e.button.button), e.type == SDL_MOUSEBUTTONDOWN);
			if(e.type == SDL_MOUSEWHEEL)
				app->scroll_event({e.wheel.x, e.wheel.y});
			if(e.type == SDL_WINDOWEVENT_RESIZED)
				app->resize_event(e.window.data1, e.window.data2);
		}

		if(accumulator >= app->fixed_time_step())
		{
			app->update(accumulator);
			accumulator = Duration{};
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

		app->frame_start();
		app->frame();
		app->frame_end();

		SDL_GL_SwapWindow(_wnd);
	}

	delete app;

	SDL_GL_DeleteContext(ctx);
	SDL_DestroyWindow(_wnd);
	_wnd = nullptr;

	SDL_Quit();
	return _exit_code;
}

glm::ivec2 Engine::framebuffer_size() const
{
	ivec2 ret;
	SDL_GL_GetDrawableSize(_wnd, &ret.x, &ret.y);
	return ret;
}

glm::ivec2 Engine::window_size() const
{
	ivec2 ret;
	SDL_GetWindowSize(_wnd, &ret.x, &ret.y);
	return ret;
}
<|endoftext|>


<commit_before>#include "SFMLSystem.hpp"

#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Window/Event.hpp>

#include "kengine.hpp"

#include "imgui-sfml/imgui-SFML.h"

#include "data/AdjustableComponent.hpp"
#include "data/ImGuiScaleComponent.hpp"

#include "functions/Execute.hpp"
#include "functions/OnEntityRemoved.hpp"
#include "functions/OnTerminate.hpp"

#include "helpers/logHelper.hpp"

#include "SFMLWindowComponent.hpp"
#include "SFMLTextureComponent.hpp"
#include "data/GraphicsComponent.hpp"

#include "data/InputBufferComponent.hpp"
#include "data/ModelComponent.hpp"
#include "data/TransformComponent.hpp"
#include "data/WindowComponent.hpp"
#include "helpers/instanceHelper.hpp"
#include "helpers/resourceHelper.hpp"

namespace kengine {
	struct sfml {
		static void init(Entity & e) noexcept {
			kengine_log(Log, "Init", "SFMLSystem");

			e += functions::Execute{ execute };
			e += functions::OnEntityCreated{ onEntityCreated };
			e += functions::OnEntityRemoved{ onEntityRemoved };
			e += functions::OnTerminate{ terminate };

			auto & scale = e.attach<ImGuiScaleComponent>();

			e += AdjustableComponent{
				"ImGui", {
					{ "scale", &scale.scale }
				}
			};
		}

		static void execute(float deltaTime) noexcept {
			const auto sfDeltaTime = g_deltaClock.restart();

			if (g_inputBuffer == nullptr) {
				for (const auto & [e, inputBuffer] : entities.with<InputBufferComponent>()) {
					g_inputBuffer = &inputBuffer;
					break;
				}
			}

			for (auto [window, sfWindow] : entities.with<SFMLWindowComponent>()) {
				updateWindowState(window, sfWindow);
				processEvents(window.id, sfWindow.window);
				render(sfWindow, sfDeltaTime);
			}
		}

		static bool updateWindowState(Entity & windowEntity, SFMLWindowComponent & sfWindowComp) noexcept {
			const auto * windowComp = windowEntity.tryGet<WindowComponent>();
			if (windowComp == nullptr) {
				windowEntity.detach<SFMLWindowComponent>();
				return false;
			}

			if (!sfWindowComp.window.isOpen()) {
				if (windowComp->shutdownOnClose)
					stopRunning();
				else
					entities -= windowEntity;
				return false;
			}

			sfWindowComp.window.setSize({ windowComp->size.x, windowComp->size.y });
			return true;
		}

		static void processEvents(EntityID window, sf::RenderWindow & sfWindow) noexcept {
			sf::Event event;
			while (sfWindow.pollEvent(event)) {
				ImGui::SFML::ProcessEvent(sfWindow, event);

				if (event.type == sf::Event::Closed)
					sfWindow.close();

				processInput(window, event);
			}
		}

		static void processInput(EntityID window, const sf::Event & e) noexcept {
			if (g_inputBuffer == nullptr)
				return;

			switch (e.type) {
				case sf::Event::KeyPressed:
				case sf::Event::KeyReleased: {
					if (ImGui::GetIO().WantCaptureKeyboard)
						break;

					g_inputBuffer->keys.push_back(InputBufferComponent::KeyEvent{
						.window = window,
						.key = e.key.code,
						.pressed = e.type == sf::Event::KeyPressed
					});
					break;
				}
				case sf::Event::MouseMoved: {
					if (ImGui::GetIO().WantCaptureMouse)
						break;

					static putils::Point2f previousPos{ 0.f, 0.f };

					const putils::Point2f pos{ (float)e.mouseMove.x, (float)e.mouseMove.y };
					const putils::Point2f rel = pos - previousPos;
					previousPos = pos;

					g_inputBuffer->moves.push_back(InputBufferComponent::MouseMoveEvent{
						.window = window,
						.pos = pos,
						.rel = rel
					});
					break;
				}
				case sf::Event::MouseButtonPressed:
				case sf::Event::MouseButtonReleased: {
					if (ImGui::GetIO().WantCaptureMouse)
						break;

					g_inputBuffer->clicks.push_back(InputBufferComponent::ClickEvent{
						.window = window,
						.pos = { (float)e.mouseButton.x, (float)e.mouseButton.y },
						.button = e.mouseButton.button,
						.pressed = e.type == sf::Event::MouseButtonPressed
					});
					break;
				}
				case sf::Event::MouseWheelScrolled: {
					if (ImGui::GetIO().WantCaptureMouse)
						return;

					g_inputBuffer->scrolls.push_back(InputBufferComponent::MouseScrollEvent{
						.window = window,
						.xoffset = 0,
						.yoffset = e.mouseWheelScroll.delta,
						.pos = { (float)e.mouseWheelScroll.x, (float)e.mouseWheelScroll.y }
					});
					break;
				}
				default:
					// don't assert, this could be a joystick event or something
					break;
			}
		}

		static void render(SFMLWindowComponent & window, sf::Time deltaTime) {
			window.window.clear();
			ImGui::SFML::Render(window.window);

			struct ZOrderedSprite {
				sf::Sprite sprite;
				float height;
			};
			std::vector<ZOrderedSprite> sprites;

			for (const auto & [e, transform, graphics] : entities.with<TransformComponent, GraphicsComponent>()) {
				const auto * texture = instanceHelper::tryGetModel<SFMLTextureComponent>(e);
				if (texture == nullptr)
					continue;

				sf::Sprite sprite(texture->texture);
				sprite.setColor(sf::Color(toColor(graphics.color).rgba));
				sprite.setPosition(transform.boundingBox.position.x, transform.boundingBox.position.z);
				sprite.setScale(transform.boundingBox.size.x, transform.boundingBox.size.y);
				sprite.setRotation(transform.yaw);
				sprites.push_back({ .sprite = std::move(sprite), .height = transform.boundingBox.position.y });
			}

			std::sort(sprites.begin(), sprites.end(), [](const auto & lhs, const auto & rhs) { return lhs.height > rhs.height; });
			for (const auto & sprite : sprites)
				window.window.draw(sprite.sprite);

			window.window.display();
			ImGui::SFML::Update(window.window, deltaTime);
		}

		static void onEntityCreated(Entity & e) noexcept {
			if (const auto * window = e.tryGet<WindowComponent>())
				createWindow(e, *window);

			if (const auto * model = e.tryGet<ModelComponent>())
				createTexture(e, *model);
		}

		static void createWindow(Entity & e, const WindowComponent & windowComp) noexcept {
			kengine_log(Log, "SFML", "Creating window '%s'", windowComp.name.c_str());

			auto & sfWindow = e.attach<SFMLWindowComponent>();
			sfWindow.window.create(
				sf::VideoMode{ windowComp.size.x, windowComp.size.y },
				windowComp.name.c_str(),
				windowComp.fullscreen ? sf::Style::Fullscreen : sf::Style::Default);

			ImGui::SFML::Init(sfWindow.window);
			ImGui::SFML::Update(sfWindow.window, g_deltaClock.restart());
		}

		static void createTexture(Entity & e, const ModelComponent & model) noexcept {
			sf::Texture texture;
			if (texture.loadFromFile(model.file.c_str())) {
				kengine_log(Log, "SFML", "Loaded texture for '%s'", model.file.c_str());
				e += SFMLTextureComponent{ std::move(texture) };
			}
		}

		static void onEntityRemoved(Entity & e) noexcept {
			if (const auto * sfWindow = e.tryGet<SFMLWindowComponent>()) {
				kengine_log(Log, "SFML", "Shutting down ImGui for window");
				ImGui::SFML::Shutdown(sfWindow->window);
			}
		}

		static void terminate() noexcept {
			kengine_log(Log, "Terminate/SFML", "Shutting down ImGui");
			ImGui::SFML::Shutdown();
		}

		static inline sf::Clock g_deltaClock;
		static inline InputBufferComponent * g_inputBuffer = nullptr;
	};
}

namespace kengine {
	EntityCreator * SFMLSystem() noexcept {
		return [](Entity & e) noexcept {
			sfml::init(e);
		};
	}
}
<commit_msg>[sfml] add logs<commit_after>#include "SFMLSystem.hpp"

#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Window/Event.hpp>

#include "kengine.hpp"

#include "imgui-sfml/imgui-SFML.h"

#include "data/AdjustableComponent.hpp"
#include "data/ImGuiScaleComponent.hpp"

#include "functions/Execute.hpp"
#include "functions/OnEntityRemoved.hpp"
#include "functions/OnTerminate.hpp"

#include "helpers/logHelper.hpp"

#include "SFMLWindowComponent.hpp"
#include "SFMLTextureComponent.hpp"
#include "data/GraphicsComponent.hpp"

#include "data/InputBufferComponent.hpp"
#include "data/ModelComponent.hpp"
#include "data/TransformComponent.hpp"
#include "data/WindowComponent.hpp"
#include "helpers/instanceHelper.hpp"
#include "helpers/resourceHelper.hpp"

namespace kengine {
	struct sfml {
		static void init(Entity & e) noexcept {
			kengine_log(Log, "Init", "SFMLSystem");

			e += functions::Execute{ execute };
			e += functions::OnEntityCreated{ onEntityCreated };
			e += functions::OnEntityRemoved{ onEntityRemoved };
			e += functions::OnTerminate{ terminate };

			auto & scale = e.attach<ImGuiScaleComponent>();

			e += AdjustableComponent{
				"ImGui", {
					{ "scale", &scale.scale }
				}
			};
		}

		static void execute(float deltaTime) noexcept {
			kengine_log(Verbose, "Execute", "SFMLSystem");

			const auto sfDeltaTime = g_deltaClock.restart();

			if (g_inputBuffer == nullptr) {
				for (const auto & [e, inputBuffer] : entities.with<InputBufferComponent>()) {
					g_inputBuffer = &inputBuffer;
					break;
				}
			}

			for (auto [window, sfWindow] : entities.with<SFMLWindowComponent>()) {
				updateWindowState(window, sfWindow);
				processEvents(window.id, sfWindow.window);
				render(sfWindow, sfDeltaTime);
			}
		}

		static bool updateWindowState(Entity & windowEntity, SFMLWindowComponent & sfWindowComp) noexcept {
			const auto * windowComp = windowEntity.tryGet<WindowComponent>();
			if (windowComp == nullptr) {
				kengine_logf(Verbose, "Execute/SFMLSystem", "%zu: destroying window as WindowComponent was removed", windowEntity.id);
				windowEntity.detach<SFMLWindowComponent>();
				return false;
			}

			if (!sfWindowComp.window.isOpen()) {
				kengine_logf(Verbose, "Execute/SFMLSystem", "%zu: window was closed", windowEntity.id);
				if (windowComp->shutdownOnClose)
					stopRunning();
				else
					entities -= windowEntity;
				return false;
			}

			sfWindowComp.window.setSize({ windowComp->size.x, windowComp->size.y });
			return true;
		}

		static void processEvents(EntityID window, sf::RenderWindow & sfWindow) noexcept {
			sf::Event event;
			while (sfWindow.pollEvent(event)) {
				ImGui::SFML::ProcessEvent(sfWindow, event);

				if (event.type == sf::Event::Closed)
					sfWindow.close();

				processInput(window, event);
			}
		}

		static void processInput(EntityID window, const sf::Event & e) noexcept {
			if (g_inputBuffer == nullptr)
				return;

			switch (e.type) {
				case sf::Event::KeyPressed:
				case sf::Event::KeyReleased: {
					if (ImGui::GetIO().WantCaptureKeyboard)
						break;

					g_inputBuffer->keys.push_back(InputBufferComponent::KeyEvent{
						.window = window,
						.key = e.key.code,
						.pressed = e.type == sf::Event::KeyPressed
					});
					break;
				}
				case sf::Event::MouseMoved: {
					if (ImGui::GetIO().WantCaptureMouse)
						break;

					static putils::Point2f previousPos{ 0.f, 0.f };

					const putils::Point2f pos{ (float)e.mouseMove.x, (float)e.mouseMove.y };
					const putils::Point2f rel = pos - previousPos;
					previousPos = pos;

					g_inputBuffer->moves.push_back(InputBufferComponent::MouseMoveEvent{
						.window = window,
						.pos = pos,
						.rel = rel
					});
					break;
				}
				case sf::Event::MouseButtonPressed:
				case sf::Event::MouseButtonReleased: {
					if (ImGui::GetIO().WantCaptureMouse)
						break;

					g_inputBuffer->clicks.push_back(InputBufferComponent::ClickEvent{
						.window = window,
						.pos = { (float)e.mouseButton.x, (float)e.mouseButton.y },
						.button = e.mouseButton.button,
						.pressed = e.type == sf::Event::MouseButtonPressed
					});
					break;
				}
				case sf::Event::MouseWheelScrolled: {
					if (ImGui::GetIO().WantCaptureMouse)
						return;

					g_inputBuffer->scrolls.push_back(InputBufferComponent::MouseScrollEvent{
						.window = window,
						.xoffset = 0,
						.yoffset = e.mouseWheelScroll.delta,
						.pos = { (float)e.mouseWheelScroll.x, (float)e.mouseWheelScroll.y }
					});
					break;
				}
				default:
					// don't assert, this could be a joystick event or something
					break;
			}
		}

		static void render(SFMLWindowComponent & window, sf::Time deltaTime) {
			window.window.clear();
			ImGui::SFML::Render(window.window);

			struct ZOrderedSprite {
				sf::Sprite sprite;
				float height;
			};
			std::vector<ZOrderedSprite> sprites;

			for (const auto & [e, transform, graphics] : entities.with<TransformComponent, GraphicsComponent>()) {
				const auto * texture = instanceHelper::tryGetModel<SFMLTextureComponent>(e);
				if (texture == nullptr)
					continue;

				sf::Sprite sprite(texture->texture);
				sprite.setColor(sf::Color(toColor(graphics.color).rgba));
				sprite.setPosition(transform.boundingBox.position.x, transform.boundingBox.position.z);
				sprite.setScale(transform.boundingBox.size.x, transform.boundingBox.size.y);
				sprite.setRotation(transform.yaw);
				sprites.push_back({ .sprite = std::move(sprite), .height = transform.boundingBox.position.y });
			}

			std::sort(sprites.begin(), sprites.end(), [](const auto & lhs, const auto & rhs) { return lhs.height > rhs.height; });
			for (const auto & sprite : sprites)
				window.window.draw(sprite.sprite);

			window.window.display();
			ImGui::SFML::Update(window.window, deltaTime);
		}

		static void onEntityCreated(Entity & e) noexcept {
			if (const auto * window = e.tryGet<WindowComponent>())
				createWindow(e, *window);

			if (const auto * model = e.tryGet<ModelComponent>())
				createTexture(e, *model);
		}

		static void createWindow(Entity & e, const WindowComponent & windowComp) noexcept {
			kengine_logf(Log, "SFML", "Creating window '%s'", windowComp.name.c_str());

			auto & sfWindow = e.attach<SFMLWindowComponent>();
			sfWindow.window.create(
				sf::VideoMode{ windowComp.size.x, windowComp.size.y },
				windowComp.name.c_str(),
				windowComp.fullscreen ? sf::Style::Fullscreen : sf::Style::Default);

			ImGui::SFML::Init(sfWindow.window);
			ImGui::SFML::Update(sfWindow.window, g_deltaClock.restart());
		}

		static void createTexture(Entity & e, const ModelComponent & model) noexcept {
			sf::Texture texture;
			if (texture.loadFromFile(model.file.c_str())) {
				kengine_logf(Log, "SFML", "Loaded texture for '%s'", model.file.c_str());
				e += SFMLTextureComponent{ std::move(texture) };
			}
		}

		static void onEntityRemoved(Entity & e) noexcept {
			if (const auto * sfWindow = e.tryGet<SFMLWindowComponent>()) {
				kengine_log(Log, "SFML", "Shutting down ImGui for window");
				ImGui::SFML::Shutdown(sfWindow->window);
			}
		}

		static void terminate() noexcept {
			kengine_log(Log, "Terminate/SFML", "Shutting down ImGui");
			ImGui::SFML::Shutdown();
		}

		static inline sf::Clock g_deltaClock;
		static inline InputBufferComponent * g_inputBuffer = nullptr;
	};
}

namespace kengine {
	EntityCreator * SFMLSystem() noexcept {
		return [](Entity & e) noexcept {
			sfml::init(e);
		};
	}
}
<|endoftext|>


<commit_before>/* Copyright 2015 Samsung Electronics Co., Ltd.
 *
 * 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 "iotjs_def.h"
#include "iotjs_module_process.h"
#include "iotjs_js.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

namespace iotjs {

static JObject* GetProcess() {
  Module* module = GetBuiltinModule(MODULE_PROCESS);
  IOTJS_ASSERT(module != NULL);

  JObject* process = module->module;
  IOTJS_ASSERT(process != NULL);
  IOTJS_ASSERT(process->IsObject());

  return process;
}

void UncaughtException(JObject& jexception) {
  JObject* process = GetProcess();

  JObject jonuncaughtexception(process->GetProperty("_onUncaughtExcecption"));
  IOTJS_ASSERT(jonuncaughtexception.IsFunction());

  JArgList args(1);
  args.Add(jexception);

  JResult jres = jonuncaughtexception.Call(*process, args);
  IOTJS_ASSERT(jres.IsOk());
}

void ProcessEmitExit(int code) {
  JObject* process = GetProcess();

  JObject jexit(process->GetProperty("emitExit"));
  IOTJS_ASSERT(jexit.IsFunction());

  JArgList args(1);
  args.Add(JVal::Number(code));

  JResult jres = jexit.Call(JObject::Null(), args);
  if (!jres.IsOk()) {
    exit(2);
  }
}

// Calls next tick callbacks registered via `process.nextTick()`.
bool ProcessNextTick() {
  JObject* process = GetProcess();

  JObject jon_next_tick(process->GetProperty("_onNextTick"));
  IOTJS_ASSERT(jon_next_tick.IsFunction());

  JResult jres = jon_next_tick.Call(JObject::Null(), JArgList::Empty());
  IOTJS_ASSERT(jres.IsOk());
  IOTJS_ASSERT(jres.value().IsBoolean());

  return jres.value().GetBoolean();
}

// Make a callback for the given `function` with `this_` binding and `args`
// arguments. The next tick callbacks registered via `process.nextTick()`
// will be called after the callback function `function` returns.
JObject MakeCallback(JObject& function, JObject& this_, JArgList& args) {
  // Calls back the function.
  JResult jres = function.Call(this_, args);
  if (jres.IsException()) {
    UncaughtException(jres.value());
  }

  // Calls the next tick callbacks.
  ProcessNextTick();

  // Return value.
  return jres.value();
}

JHANDLER_FUNCTION(Binding, handler) {
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsNumber());

  int module_kind = handler.GetArg(0)->GetInt32();

  Module* module = GetBuiltinModule(static_cast<ModuleKind>(module_kind));
  IOTJS_ASSERT(module != NULL);

  if (module->module == NULL) {
    IOTJS_ASSERT(module->fn_register != NULL);
    module->module = module->fn_register();
    IOTJS_ASSERT(module->module);
  }

  handler.Return(*module->module);

  return true;
}

static JResult WrapEval(const String& source) {
  static const char* wrapper[2] = {
      "(function (a, b, c) { function wwwwrap(exports, require, module) {\n",
      "}; wwwwrap(a, b, c); });\n" };

  int len1 = strlen(wrapper[0]);
  int len2 = strlen(source.data());
  int len3 = strlen(wrapper[1]);

  String code("", len1 + len2 + len3 + 1);
  strcpy(code.data(), wrapper[0]);
  strcat(code.data() + len1, source.data());
  strcat(code.data() + len1 + len2, wrapper[1]);

  return JObject::Eval(code);
}

JHANDLER_FUNCTION(Compile, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsString());

  String source = handler.GetArg(0)->GetString();

  JResult jres = WrapEval(source);

  if (jres.IsOk()) {
    handler.Return(jres.value());
  } else {
    handler.Throw(jres.value());
  }

  return !handler.HasThrown();
}

JHANDLER_FUNCTION(CompileNativePtr, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsObject());

  String source((const char*)handler.GetArg(0)->GetNative());

  JResult jres = WrapEval(source);

  if (jres.IsOk()) {
    handler.Return(jres.value());
  } else {
    handler.Throw(jres.value());
  }

  return !handler.HasThrown();
}

JHANDLER_FUNCTION(ReadSource, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsString());

  String path = handler.GetArg(0)->GetString();
  String code = ReadFile(path.data());

  JObject ret(code);
  handler.Return(ret);

  return true;
}

JHANDLER_FUNCTION(Cwd, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 0);

  char path[IOTJS_MAX_PATH_SIZE];
  size_t size_path = sizeof(path);
  int err = uv_cwd(path, &size_path);
  if (err) {
    JHANDLER_THROW_RETURN(handler, Error, "cwd error");
  }
  JObject ret(path);
  handler.Return(ret);

  return true;
}

JHANDLER_FUNCTION(DoExit, handler) {
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsNumber());

  int exit_code = handler.GetArg(0)->GetInt32();

  exit(exit_code);
}

// Initialize `process.argv`
JHANDLER_FUNCTION(InitArgv, handler) {
  IOTJS_ASSERT(handler.GetThis()->IsObject());

  // environtment
  Environment* env = Environment::GetEnv();

  // process.argv
  JObject jargv = handler.GetThis()->GetProperty("argv");

  for (int i = 0; i < env->argc(); ++i) {
    char index[10] = {0};
    sprintf(index, "%d", i);
    JObject value(env->argv()[i]);
    jargv.SetProperty(index, value);
  }

  return true;
}

void SetNativeSources(JObject* native_sources) {
  for (int i = 0; natives[i].name; i++) {
    JObject native_source;
    native_source.SetNative((uintptr_t)(natives[i].source), NULL);
    native_sources->SetProperty(natives[i].name, native_source);
  }
}

static void SetProcessEnv(JObject* process){
  const char *homedir;
  homedir = getenv("HOME");
  if (homedir == NULL) {
    homedir = "";
  }
  JObject home(homedir);
  JObject env;
  env.SetProperty("HOME", home);
  process->SetProperty("env", env);
}

static void SetProcessIotjs(JObject* process) {
  // IoT.js specific
  JObject iotjs;
  process->SetProperty("iotjs", iotjs);

  JObject jboard(TARGET_BOARD);
  iotjs.SetProperty("board", jboard);
}

JObject* InitProcess() {
  Module* module = GetBuiltinModule(MODULE_PROCESS);
  JObject* process = module->module;

  if (process == NULL) {
    process = new JObject();
    process->SetMethod("binding", Binding);
    process->SetMethod("compile", Compile);
    process->SetMethod("compileNativePtr", CompileNativePtr);
    process->SetMethod("readSource", ReadSource);
    process->SetMethod("cwd", Cwd);
    process->SetMethod("doExit", DoExit);
    process->SetMethod("_initArgv", InitArgv);
    SetProcessEnv(process);

    // process.native_sources
    JObject native_sources;
    SetNativeSources(&native_sources);
    process->SetProperty("native_sources", native_sources);

    // process.platform
    JObject platform(TARGET_OS);
    process->SetProperty("platform", platform);

    // process.arch
    JObject arch(TARGET_ARCH);
    process->SetProperty("arch", arch);

    // Set iotjs
    SetProcessIotjs(process);

    // Binding module id.
    JObject jbinding = process->GetProperty("binding");

#define ENUMDEF_MODULE_LIST(upper, Camel, lower) \
    jbinding.SetProperty(#lower, JVal::Number(MODULE_ ## upper));

    MAP_MODULE_LIST(ENUMDEF_MODULE_LIST)

#undef ENUMDEF_MODULE_LIST

    module->module = process;
  }

  return process;
}

} // namespace iotjs
<commit_msg>Fixed double module wrapper for #47<commit_after>/* Copyright 2015 Samsung Electronics Co., Ltd.
 *
 * 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 "iotjs_def.h"
#include "iotjs_module_process.h"
#include "iotjs_js.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

namespace iotjs {

static JObject* GetProcess() {
  Module* module = GetBuiltinModule(MODULE_PROCESS);
  IOTJS_ASSERT(module != NULL);

  JObject* process = module->module;
  IOTJS_ASSERT(process != NULL);
  IOTJS_ASSERT(process->IsObject());

  return process;
}

void UncaughtException(JObject& jexception) {
  JObject* process = GetProcess();

  JObject jonuncaughtexception(process->GetProperty("_onUncaughtExcecption"));
  IOTJS_ASSERT(jonuncaughtexception.IsFunction());

  JArgList args(1);
  args.Add(jexception);

  JResult jres = jonuncaughtexception.Call(*process, args);
  IOTJS_ASSERT(jres.IsOk());
}

void ProcessEmitExit(int code) {
  JObject* process = GetProcess();

  JObject jexit(process->GetProperty("emitExit"));
  IOTJS_ASSERT(jexit.IsFunction());

  JArgList args(1);
  args.Add(JVal::Number(code));

  JResult jres = jexit.Call(JObject::Null(), args);
  if (!jres.IsOk()) {
    exit(2);
  }
}

// Calls next tick callbacks registered via `process.nextTick()`.
bool ProcessNextTick() {
  JObject* process = GetProcess();

  JObject jon_next_tick(process->GetProperty("_onNextTick"));
  IOTJS_ASSERT(jon_next_tick.IsFunction());

  JResult jres = jon_next_tick.Call(JObject::Null(), JArgList::Empty());
  IOTJS_ASSERT(jres.IsOk());
  IOTJS_ASSERT(jres.value().IsBoolean());

  return jres.value().GetBoolean();
}

// Make a callback for the given `function` with `this_` binding and `args`
// arguments. The next tick callbacks registered via `process.nextTick()`
// will be called after the callback function `function` returns.
JObject MakeCallback(JObject& function, JObject& this_, JArgList& args) {
  // Calls back the function.
  JResult jres = function.Call(this_, args);
  if (jres.IsException()) {
    UncaughtException(jres.value());
  }

  // Calls the next tick callbacks.
  ProcessNextTick();

  // Return value.
  return jres.value();
}

JHANDLER_FUNCTION(Binding, handler) {
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsNumber());

  int module_kind = handler.GetArg(0)->GetInt32();

  Module* module = GetBuiltinModule(static_cast<ModuleKind>(module_kind));
  IOTJS_ASSERT(module != NULL);

  if (module->module == NULL) {
    IOTJS_ASSERT(module->fn_register != NULL);
    module->module = module->fn_register();
    IOTJS_ASSERT(module->module);
  }

  handler.Return(*module->module);

  return true;
}

static JResult WrapEval(const String& source) {
  static const char* wrapper[2] = {
      "(function(exports, require, module) {\n",
      "});\n" };

  int len1 = strlen(wrapper[0]);
  int len2 = strlen(source.data());
  int len3 = strlen(wrapper[1]);

  String code("", len1 + len2 + len3 + 1);
  strcpy(code.data(), wrapper[0]);
  strcat(code.data() + len1, source.data());
  strcat(code.data() + len1 + len2, wrapper[1]);

  return JObject::Eval(code);
}

JHANDLER_FUNCTION(Compile, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsString());

  String source = handler.GetArg(0)->GetString();

  JResult jres = WrapEval(source);

  if (jres.IsOk()) {
    handler.Return(jres.value());
  } else {
    handler.Throw(jres.value());
  }

  return !handler.HasThrown();
}

JHANDLER_FUNCTION(CompileNativePtr, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsObject());

  String source((const char*)handler.GetArg(0)->GetNative());

  JResult jres = WrapEval(source);

  if (jres.IsOk()) {
    handler.Return(jres.value());
  } else {
    handler.Throw(jres.value());
  }

  return !handler.HasThrown();
}

JHANDLER_FUNCTION(ReadSource, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsString());

  String path = handler.GetArg(0)->GetString();
  String code = ReadFile(path.data());

  JObject ret(code);
  handler.Return(ret);

  return true;
}

JHANDLER_FUNCTION(Cwd, handler){
  IOTJS_ASSERT(handler.GetArgLength() == 0);

  char path[IOTJS_MAX_PATH_SIZE];
  size_t size_path = sizeof(path);
  int err = uv_cwd(path, &size_path);
  if (err) {
    JHANDLER_THROW_RETURN(handler, Error, "cwd error");
  }
  JObject ret(path);
  handler.Return(ret);

  return true;
}

JHANDLER_FUNCTION(DoExit, handler) {
  IOTJS_ASSERT(handler.GetArgLength() == 1);
  IOTJS_ASSERT(handler.GetArg(0)->IsNumber());

  int exit_code = handler.GetArg(0)->GetInt32();

  exit(exit_code);
}

// Initialize `process.argv`
JHANDLER_FUNCTION(InitArgv, handler) {
  IOTJS_ASSERT(handler.GetThis()->IsObject());

  // environtment
  Environment* env = Environment::GetEnv();

  // process.argv
  JObject jargv = handler.GetThis()->GetProperty("argv");

  for (int i = 0; i < env->argc(); ++i) {
    char index[10] = {0};
    sprintf(index, "%d", i);
    JObject value(env->argv()[i]);
    jargv.SetProperty(index, value);
  }

  return true;
}

void SetNativeSources(JObject* native_sources) {
  for (int i = 0; natives[i].name; i++) {
    JObject native_source;
    native_source.SetNative((uintptr_t)(natives[i].source), NULL);
    native_sources->SetProperty(natives[i].name, native_source);
  }
}

static void SetProcessEnv(JObject* process){
  const char *homedir;
  homedir = getenv("HOME");
  if (homedir == NULL) {
    homedir = "";
  }
  JObject home(homedir);
  JObject env;
  env.SetProperty("HOME", home);
  process->SetProperty("env", env);
}

static void SetProcessIotjs(JObject* process) {
  // IoT.js specific
  JObject iotjs;
  process->SetProperty("iotjs", iotjs);

  JObject jboard(TARGET_BOARD);
  iotjs.SetProperty("board", jboard);
}

JObject* InitProcess() {
  Module* module = GetBuiltinModule(MODULE_PROCESS);
  JObject* process = module->module;

  if (process == NULL) {
    process = new JObject();
    process->SetMethod("binding", Binding);
    process->SetMethod("compile", Compile);
    process->SetMethod("compileNativePtr", CompileNativePtr);
    process->SetMethod("readSource", ReadSource);
    process->SetMethod("cwd", Cwd);
    process->SetMethod("doExit", DoExit);
    process->SetMethod("_initArgv", InitArgv);
    SetProcessEnv(process);

    // process.native_sources
    JObject native_sources;
    SetNativeSources(&native_sources);
    process->SetProperty("native_sources", native_sources);

    // process.platform
    JObject platform(TARGET_OS);
    process->SetProperty("platform", platform);

    // process.arch
    JObject arch(TARGET_ARCH);
    process->SetProperty("arch", arch);

    // Set iotjs
    SetProcessIotjs(process);

    // Binding module id.
    JObject jbinding = process->GetProperty("binding");

#define ENUMDEF_MODULE_LIST(upper, Camel, lower) \
    jbinding.SetProperty(#lower, JVal::Number(MODULE_ ## upper));

    MAP_MODULE_LIST(ENUMDEF_MODULE_LIST)

#undef ENUMDEF_MODULE_LIST

    module->module = process;
  }

  return process;
}

} // namespace iotjs
<|endoftext|>