<commit_before>#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/shm.h>

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

#include "tangram.h"
#include "platform.h"
#include "gl.h"

#include "util/shaderProgram.h"
#include "util/vertexLayout.h"
#include "util/typedMesh.h"
#include "util/geom.h"

#define KEY_ESC      113    // q
#define KEY_ZOOM_IN  45     // -
#define KEY_ZOOM_OUT 61     // =
#define KEY_UP       119    // w
#define KEY_LEFT     97     // a
#define KEY_RIGHT    115    // s
#define KEY_DOWN     122    // z

struct timeval tv;

typedef struct {
    uint32_t screen_width;
    uint32_t screen_height;

    // OpenGL|ES objects
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;

} CUBE_STATE_T;
static CUBE_STATE_T _state, *state=&_state;

typedef struct Mouse {
    Mouse():x(0),y(0),button(0){};

    float   x,y;
    float   velX,velY;
    int     button;
};
static Mouse mouse;
bool bMouse = false;
float mouseSize = 100.0f;

std::shared_ptr<ShaderProgram> mouseShader;
std::string mouseVertex =
"precision mediump float;\n"
"uniform float u_time;\n"
"uniform vec2 u_mouse;\n"
"uniform vec2 u_resolution;\n"
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"attribute vec2 a_texcoord;\n"
"varying vec4 v_color;\n"
"varying vec2 v_texcoord;\n"
"void main() {\n"
"    v_texcoord = a_texcoord;\n"
"    v_color = a_color;\n"
"    vec2 mouse = vec2(u_mouse/u_resolution)*4.0-2.0;\n"
"    gl_Position = a_position+vec4(mouse,0.0,1.0);\n"
"}\n";

std::string mouseFragment =
"precision mediump float;\n"
"uniform float u_time;\n"
"uniform vec2 u_mouse;\n"
"uniform vec2 u_resolution;\n"
"varying vec4 v_color;\n"
"varying vec2 v_texcoord;\n"
"\n"
"float box(in vec2 _st, in vec2 _size){\n"
"    _size = vec2(0.5) - _size*0.5;\n"
"    vec2 uv = smoothstep(_size, _size+vec2(0.001), _st);\n"
"    uv *= smoothstep(_size, _size+vec2(0.001), vec2(1.0)-_st);\n"
"    return uv.x*uv.y;\n"
"}\n"
"\n"
"float cross(in vec2 _st, float _size){\n"
"    return  box(_st, vec2(_size,_size/6.)) + box(_st, vec2(_size/6.,_size));\n"
"}\n"
"void main() {\n"
"    gl_FragColor = v_color * cross(v_texcoord, 0.9 );\n"
"}\n";

struct PosUVColorVertex {
    // Position Data
    GLfloat pos_x;
    GLfloat pos_y;
    GLfloat pos_z;
    // UV Data
    GLfloat texcoord_x;
    GLfloat texcoord_y;
    // Color Data
    GLuint abgr;
};
typedef TypedMesh<PosUVColorVertex> Mesh;
std::shared_ptr<Mesh> mouseMesh;

static void initOpenGL(){
    bcm_host_init();

    // Clear application state
    memset( state, 0, sizeof( *state ) );

    int32_t success = 0;
    EGLBoolean result;
    EGLint num_config;

    static EGL_DISPMANX_WINDOW_T nativewindow;

    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_DEPTH_SIZE, 16,
        EGL_NONE
    };

    static const EGLint context_attributes[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE
    };
    EGLConfig config;

    // get an EGL display connection
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    assert(state->display!=EGL_NO_DISPLAY);

    // initialize the EGL display connection
    result = eglInitialize(state->display, NULL, NULL);
    assert(EGL_FALSE != result);

    // get an appropriate EGL frame buffer configuration
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
    assert(EGL_FALSE != result);

    // get an appropriate EGL frame buffer configuration
    result = eglBindAPI(EGL_OPENGL_ES_API);
    assert(EGL_FALSE != result);

    // create an EGL rendering context
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes);
    assert(state->context!=EGL_NO_CONTEXT);

    // create an EGL window surface
    success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
    assert( success >= 0 );

    dst_rect.x = 0;
    dst_rect.y = 0;
    dst_rect.width = state->screen_width;
    dst_rect.height = state->screen_height;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = state->screen_width << 16;
    src_rect.height = state->screen_height << 16;

    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );
    dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
                                               0/*layer*/, &dst_rect, 0/*src*/,
                                               &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);

    nativewindow.element = dispman_element;
    nativewindow.width = state->screen_width;
    nativewindow.height = state->screen_height;
    vc_dispmanx_update_submit_sync( dispman_update );

    state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
    assert(state->surface != EGL_NO_SURFACE);

    // connect the context to the surface
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
    assert(EGL_FALSE != result);

    // Set background color and clear buffers
    glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
    glClear( GL_COLOR_BUFFER_BIT );

    // Prepare viewport
    glViewport( 0, 0, state->screen_width, state->screen_height );

    // Prepair Mouse Shader
    if (bMouse) {
        mouseShader = std::shared_ptr<ShaderProgram>(new ShaderProgram());
        mouseShader->setSourceStrings(mouseFragment, mouseVertex );

        std::shared_ptr<VertexLayout> vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
            {"a_position", 3, GL_FLOAT, false, 0},
            {"a_texcoord", 2, GL_FLOAT, false, 0},
            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0}
        }));

        std::vector<PosUVColorVertex> vertices;
        std::vector<int> indices;

        // Small billboard for the mouse
        GLuint color = 0xffffffff;
        {
            float x = -mouseSize*0.5f/state->screen_width;
            float y = -mouseSize*0.5f/state->screen_height;
            float w = mouseSize/state->screen_width;
            float h = mouseSize/state->screen_height;

            vertices.push_back({ x, y, 0.0, 0.0, 0.0, color});
            vertices.push_back({ x+w, y, 0.0, 0.0, 1.0, color});
            vertices.push_back({ x+w, y+h, 0.0, 1.0, 1.0, color});
            vertices.push_back({ x, y+h, 0.0, 0.0, 1.0, color });

            indices.push_back(0); indices.push_back(1); indices.push_back(2);
            indices.push_back(2); indices.push_back(3); indices.push_back(0);
        }

        mouseMesh = std::shared_ptr<Mesh>(new Mesh(vertexLayout, GL_TRIANGLES));
        mouseMesh->addVertices(std::move(vertices), std::move(indices));
        mouseMesh->compileVertexBuffer();
    }
}

static bool updateMouse(){
    static int fd = -1;
    const int width=state->screen_width, height=state->screen_height;
    //static int x=width, y=height;
    const int XSIGN = 1<<4, YSIGN = 1<<5;
    if (fd<0) {
        fd = open("/dev/input/mouse0",O_RDONLY|O_NONBLOCK);
    }
    if (fd>=0) {

        // Set values to 0
        mouse.velX=0;
        mouse.velY=0;

        // Extract values from driver
        struct {char buttons, dx, dy; } m;
        while (1) {
            int bytes = read(fd, &m, sizeof m);

            if (bytes < (int)sizeof m) {
                return false;
            } else if (m.buttons&8) {
                break; // This bit should always be set
            }

            read(fd, &m, 1); // Try to sync up again
        }

        // Set button value
        if (m.buttons&3)
            mouse.button = m.buttons&3;
        else
            mouse.button = 0;

        // Set deltas
        mouse.velX=m.dx;
        mouse.velY=m.dy;
        if (m.buttons&XSIGN) mouse.velX-=256;
        if (m.buttons&YSIGN) mouse.velY-=256;

        // Add movement
        mouse.x+=mouse.velX;
        mouse.y+=mouse.velY;

        // Clamp values
        if (mouse.x<0) mouse.x=0;
        if (mouse.y<0) mouse.y=0;
        if (mouse.x>width) mouse.x=width;
        if (mouse.y>height) mouse.y=height;
        return true;
    }
    return false;
}

int getkey() {
    int character;
    struct termios orig_term_attr;
    struct termios new_term_attr;

    /* set the terminal to raw mode */
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    new_term_attr.c_cc[VTIME] = 0;
    new_term_attr.c_cc[VMIN] = 0;
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    /* read a character from the stdin stream without blocking */
    /*   returns EOF (-1) if no character is available */
    character = fgetc(stdin);

    /* restore the original terminal attributes */
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return character;
}

//==============================================================================
int main(int argc, char **argv){

    for (int i = 1; i < argc ; i++){
        if ( std::string(argv[i]) == "-m" ){
            bMouse = true;
        }
    }

    // Start OpenGL context
    initOpenGL();

    // Set background color and clear buffers
    Tangram::initialize();
    Tangram::resize(state->screen_width, state->screen_height);

    // Start clock
    gettimeofday(&tv, NULL);
    unsigned long long timePrev = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
    unsigned long long timeStart = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;

    bool bContinue = true;
    while (bContinue) {

        // Update
        unsigned long long timeNow = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
        double delta = (timeNow - timePrev)*0.001;
        float time = (timeNow - timeStart)*0.001;

        Tangram::update(delta);
        timePrev = timeNow;

        if(updateMouse()){
            if( mouse.button == 1 ){
                Tangram::handlePanGesture(  mouse.x-mouse.velX*1.0,
                                            mouse.y+mouse.velY*1.0,
                                            mouse.x,
                                            mouse.y);
            } else if( mouse.button == 2 ){
                Tangram::handlePinchGesture( 0.0, 0.0, 1.0 + mouse.velY*0.001);
            }
        }

        int key = getkey();
        if(key != -1){
            switch (key) {
                case KEY_ZOOM_IN:
                    Tangram::handlePinchGesture(0.0,0.0,0.5);
                    break;
                case KEY_ZOOM_OUT:
                    Tangram::handlePinchGesture(0.0,0.0,2.0);
                    break;
                case KEY_UP:
                    Tangram::handlePanGesture(0.0,0.0,0.0,100.0);
                    break;
                case KEY_DOWN:
                    Tangram::handlePanGesture(0.0,0.0,0.0,-100.0);
                    break;
                case KEY_LEFT:
                    Tangram::handlePanGesture(0.0,0.0,100.0,0.0);
                    break;
                case KEY_RIGHT:
                    Tangram::handlePanGesture(0.0,0.0,-100.0,0.0);
                    break;
                case KEY_ESC:
                    bContinue = false;
                    break;
                default:
                    logMsg(" -> %i\n",key);
            }
        }

        // Render
        Tangram::render();

        if (bMouse) {
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDisable(GL_DEPTH_TEST);
            mouseShader->use();
            mouseShader->setUniformf("u_time", time);
            mouseShader->setUniformf("u_mouse", mouse.x, mouse.y);
            mouseShader->setUniformf("u_resolution",state->screen_width, state->screen_height);
            mouseMesh->draw(mouseShader);
            glDisable(GL_BLEND);
            glEnable(GL_DEPTH_TEST);
        }

        eglSwapBuffers(state->display, state->surface);
    }

    Tangram::teardown();
    return 0;
}
<commit_msg>fixing zoom from the center on RPI when dragging w right buttom<commit_after>#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/shm.h>

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

#include "tangram.h"
#include "platform.h"
#include "gl.h"

#include "util/shaderProgram.h"
#include "util/vertexLayout.h"
#include "util/typedMesh.h"
#include "util/geom.h"

#define KEY_ESC      113    // q
#define KEY_ZOOM_IN  45     // -
#define KEY_ZOOM_OUT 61     // =
#define KEY_UP       119    // w
#define KEY_LEFT     97     // a
#define KEY_RIGHT    115    // s
#define KEY_DOWN     122    // z

struct timeval tv;

typedef struct {
    uint32_t screen_width;
    uint32_t screen_height;

    // OpenGL|ES objects
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;

} CUBE_STATE_T;
static CUBE_STATE_T _state, *state=&_state;

typedef struct Mouse {
    Mouse():x(0),y(0),button(0){};

    float   x,y;
    float   velX,velY;
    int     button;
};
static Mouse mouse;
bool bMouse = false;
float mouseSize = 100.0f;

std::shared_ptr<ShaderProgram> mouseShader;
std::string mouseVertex =
"precision mediump float;\n"
"uniform float u_time;\n"
"uniform vec2 u_mouse;\n"
"uniform vec2 u_resolution;\n"
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"attribute vec2 a_texcoord;\n"
"varying vec4 v_color;\n"
"varying vec2 v_texcoord;\n"
"void main() {\n"
"    v_texcoord = a_texcoord;\n"
"    v_color = a_color;\n"
"    vec2 mouse = vec2(u_mouse/u_resolution)*4.0-2.0;\n"
"    gl_Position = a_position+vec4(mouse,0.0,1.0);\n"
"}\n";

std::string mouseFragment =
"precision mediump float;\n"
"uniform float u_time;\n"
"uniform vec2 u_mouse;\n"
"uniform vec2 u_resolution;\n"
"varying vec4 v_color;\n"
"varying vec2 v_texcoord;\n"
"\n"
"float box(in vec2 _st, in vec2 _size){\n"
"    _size = vec2(0.5) - _size*0.5;\n"
"    vec2 uv = smoothstep(_size, _size+vec2(0.001), _st);\n"
"    uv *= smoothstep(_size, _size+vec2(0.001), vec2(1.0)-_st);\n"
"    return uv.x*uv.y;\n"
"}\n"
"\n"
"float cross(in vec2 _st, float _size){\n"
"    return  box(_st, vec2(_size,_size/6.)) + box(_st, vec2(_size/6.,_size));\n"
"}\n"
"void main() {\n"
"    gl_FragColor = v_color * cross(v_texcoord, 0.9 );\n"
"}\n";

struct PosUVColorVertex {
    // Position Data
    GLfloat pos_x;
    GLfloat pos_y;
    GLfloat pos_z;
    // UV Data
    GLfloat texcoord_x;
    GLfloat texcoord_y;
    // Color Data
    GLuint abgr;
};
typedef TypedMesh<PosUVColorVertex> Mesh;
std::shared_ptr<Mesh> mouseMesh;

static void initOpenGL(){
    bcm_host_init();

    // Clear application state
    memset( state, 0, sizeof( *state ) );

    int32_t success = 0;
    EGLBoolean result;
    EGLint num_config;

    static EGL_DISPMANX_WINDOW_T nativewindow;

    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_DEPTH_SIZE, 16,
        EGL_NONE
    };

    static const EGLint context_attributes[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE
    };
    EGLConfig config;

    // get an EGL display connection
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    assert(state->display!=EGL_NO_DISPLAY);

    // initialize the EGL display connection
    result = eglInitialize(state->display, NULL, NULL);
    assert(EGL_FALSE != result);

    // get an appropriate EGL frame buffer configuration
    result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
    assert(EGL_FALSE != result);

    // get an appropriate EGL frame buffer configuration
    result = eglBindAPI(EGL_OPENGL_ES_API);
    assert(EGL_FALSE != result);

    // create an EGL rendering context
    state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes);
    assert(state->context!=EGL_NO_CONTEXT);

    // create an EGL window surface
    success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
    assert( success >= 0 );

    dst_rect.x = 0;
    dst_rect.y = 0;
    dst_rect.width = state->screen_width;
    dst_rect.height = state->screen_height;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = state->screen_width << 16;
    src_rect.height = state->screen_height << 16;

    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );
    dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
                                               0/*layer*/, &dst_rect, 0/*src*/,
                                               &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);

    nativewindow.element = dispman_element;
    nativewindow.width = state->screen_width;
    nativewindow.height = state->screen_height;
    vc_dispmanx_update_submit_sync( dispman_update );

    state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
    assert(state->surface != EGL_NO_SURFACE);

    // connect the context to the surface
    result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
    assert(EGL_FALSE != result);

    // Set background color and clear buffers
    glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
    glClear( GL_COLOR_BUFFER_BIT );

    // Prepare viewport
    glViewport( 0, 0, state->screen_width, state->screen_height );

    // Prepair Mouse Shader
    if (bMouse) {
        mouseShader = std::shared_ptr<ShaderProgram>(new ShaderProgram());
        mouseShader->setSourceStrings(mouseFragment, mouseVertex );

        std::shared_ptr<VertexLayout> vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
            {"a_position", 3, GL_FLOAT, false, 0},
            {"a_texcoord", 2, GL_FLOAT, false, 0},
            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0}
        }));

        std::vector<PosUVColorVertex> vertices;
        std::vector<int> indices;

        // Small billboard for the mouse
        GLuint color = 0xffffffff;
        {
            float x = -mouseSize*0.5f/state->screen_width;
            float y = -mouseSize*0.5f/state->screen_height;
            float w = mouseSize/state->screen_width;
            float h = mouseSize/state->screen_height;

            vertices.push_back({ x, y, 0.0, 0.0, 0.0, color});
            vertices.push_back({ x+w, y, 0.0, 0.0, 1.0, color});
            vertices.push_back({ x+w, y+h, 0.0, 1.0, 1.0, color});
            vertices.push_back({ x, y+h, 0.0, 0.0, 1.0, color });

            indices.push_back(0); indices.push_back(1); indices.push_back(2);
            indices.push_back(2); indices.push_back(3); indices.push_back(0);
        }

        mouseMesh = std::shared_ptr<Mesh>(new Mesh(vertexLayout, GL_TRIANGLES));
        mouseMesh->addVertices(std::move(vertices), std::move(indices));
        mouseMesh->compileVertexBuffer();
    }
}

static bool updateMouse(){
    static int fd = -1;
    const int width=state->screen_width, height=state->screen_height;
    //static int x=width, y=height;
    const int XSIGN = 1<<4, YSIGN = 1<<5;
    if (fd<0) {
        fd = open("/dev/input/mouse0",O_RDONLY|O_NONBLOCK);
    }
    if (fd>=0) {

        // Set values to 0
        mouse.velX=0;
        mouse.velY=0;

        // Extract values from driver
        struct {char buttons, dx, dy; } m;
        while (1) {
            int bytes = read(fd, &m, sizeof m);

            if (bytes < (int)sizeof m) {
                return false;
            } else if (m.buttons&8) {
                break; // This bit should always be set
            }

            read(fd, &m, 1); // Try to sync up again
        }

        // Set button value
        if (m.buttons&3)
            mouse.button = m.buttons&3;
        else
            mouse.button = 0;

        // Set deltas
        mouse.velX=m.dx;
        mouse.velY=m.dy;
        if (m.buttons&XSIGN) mouse.velX-=256;
        if (m.buttons&YSIGN) mouse.velY-=256;

        // Add movement
        mouse.x+=mouse.velX;
        mouse.y+=mouse.velY;

        // Clamp values
        if (mouse.x<0) mouse.x=0;
        if (mouse.y<0) mouse.y=0;
        if (mouse.x>width) mouse.x=width;
        if (mouse.y>height) mouse.y=height;
        return true;
    }
    return false;
}

int getkey() {
    int character;
    struct termios orig_term_attr;
    struct termios new_term_attr;

    /* set the terminal to raw mode */
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    new_term_attr.c_cc[VTIME] = 0;
    new_term_attr.c_cc[VMIN] = 0;
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    /* read a character from the stdin stream without blocking */
    /*   returns EOF (-1) if no character is available */
    character = fgetc(stdin);

    /* restore the original terminal attributes */
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return character;
}

//==============================================================================
int main(int argc, char **argv){

    for (int i = 1; i < argc ; i++){
        if ( std::string(argv[i]) == "-m" ){
            bMouse = true;
        }
    }

    // Start OpenGL context
    initOpenGL();

    // Set background color and clear buffers
    Tangram::initialize();
    Tangram::resize(state->screen_width, state->screen_height);

    // Start clock
    gettimeofday(&tv, NULL);
    unsigned long long timePrev = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
    unsigned long long timeStart = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;

    bool bContinue = true;
    while (bContinue) {

        // Update
        unsigned long long timeNow = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
        double delta = (timeNow - timePrev)*0.001;
        float time = (timeNow - timeStart)*0.001;

        Tangram::update(delta);
        timePrev = timeNow;

        if(updateMouse()){
            if( mouse.button == 1 ){
                Tangram::handlePanGesture(  mouse.x-mouse.velX*1.0,
                                            mouse.y+mouse.velY*1.0,
                                            mouse.x,
                                            mouse.y);
            } else if( mouse.button == 2 ){
                Tangram::handlePinchGesture( state->screen_width/2.0, state->screen_height/2.0, 1.0 + mouse.velY*0.001);
            }
        }

        int key = getkey();
        if(key != -1){
            switch (key) {
                case KEY_ZOOM_IN:
                    Tangram::handlePinchGesture(0.0,0.0,0.5);
                    break;
                case KEY_ZOOM_OUT:
                    Tangram::handlePinchGesture(0.0,0.0,2.0);
                    break;
                case KEY_UP:
                    Tangram::handlePanGesture(0.0,0.0,0.0,100.0);
                    break;
                case KEY_DOWN:
                    Tangram::handlePanGesture(0.0,0.0,0.0,-100.0);
                    break;
                case KEY_LEFT:
                    Tangram::handlePanGesture(0.0,0.0,100.0,0.0);
                    break;
                case KEY_RIGHT:
                    Tangram::handlePanGesture(0.0,0.0,-100.0,0.0);
                    break;
                case KEY_ESC:
                    bContinue = false;
                    break;
                default:
                    logMsg(" -> %i\n",key);
            }
        }

        // Render
        Tangram::render();

        if (bMouse) {
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDisable(GL_DEPTH_TEST);
            mouseShader->use();
            mouseShader->setUniformf("u_time", time);
            mouseShader->setUniformf("u_mouse", mouse.x, mouse.y);
            mouseShader->setUniformf("u_resolution",state->screen_width, state->screen_height);
            mouseMesh->draw(mouseShader);
            glDisable(GL_BLEND);
            glEnable(GL_DEPTH_TEST);
        }

        eglSwapBuffers(state->display, state->surface);
    }

    Tangram::teardown();
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"

using base::Time;
using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::UnrecoverableErrorHandler;
using sync_api::SyncManager;
using testing::_;
using testing::DoAll;
using testing::DoDefault;
using testing::Return;
using testing::SetArgumentPointee;

class TestAutofillModelAssociator
    : public TestModelAssociator<AutofillModelAssociator> {
 public:
  TestAutofillModelAssociator(ProfileSyncService* service,
                              WebDatabase* web_database,
                              UnrecoverableErrorHandler* error_handler)
      : TestModelAssociator<AutofillModelAssociator>(
          service, web_database, error_handler) {
  }
};

class WebDatabaseMock : public WebDatabase {
 public:
  MOCK_METHOD2(RemoveFormElement,
               bool(const string16& name, const string16& value));
  MOCK_METHOD1(GetAllAutofillEntries,
               bool(std::vector<AutofillEntry>* entries));
  MOCK_METHOD3(GetAutofillTimestamps,
               bool(const string16& name,
                    const string16& value,
                    std::vector<base::Time>* timestamps));
  MOCK_METHOD1(UpdateAutofillEntries,
               bool(const std::vector<AutofillEntry>& entries));
};

class ProfileMock : public TestingProfile {
 public:
  MOCK_METHOD1(GetWebDataService, WebDataService*(ServiceAccessType access));
};

class DBThreadNotificationService :
    public base::RefCountedThreadSafe<DBThreadNotificationService> {
 public:
  DBThreadNotificationService() : done_event_(false, false) {}

  void Init() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::InitTask));
    done_event_.Wait();
  }

  void TearDown() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::TearDownTask));
    done_event_.Wait();
  }

 private:
  friend class base::RefCountedThreadSafe<DBThreadNotificationService>;

  void InitTask() {
    service_.reset(new NotificationService());
    done_event_.Signal();
  }

  void TearDownTask() {
    service_.reset(NULL);
    done_event_.Signal();
  }

  WaitableEvent done_event_;
  scoped_ptr<NotificationService> service_;
};

class WebDataServiceFake : public WebDataService {
 public:
  virtual bool IsDatabaseLoaded() {
    return true;
  }

  // Note that we inject the WebDatabase through the
  // ProfileSyncFactory mock.
  virtual WebDatabase* GetDatabase() {
    return NULL;
  }
};

ACTION(QuitUIMessageLoop) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  MessageLoop::current()->Quit();
}

ACTION_P3(MakeAutofillSyncComponents, service, wd, dtc) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  AutofillModelAssociator* model_associator =
      new TestAutofillModelAssociator(service, wd, dtc);
  AutofillChangeProcessor* change_processor =
      new AutofillChangeProcessor(model_associator, wd, service);
  return ProfileSyncFactory::SyncComponents(model_associator, change_processor);
}

class ProfileSyncServiceAutofillTest : public testing::Test {
 protected:
  ProfileSyncServiceAutofillTest()
      : ui_thread_(ChromeThread::UI, &message_loop_),
        db_thread_(ChromeThread::DB),
        done_event_(false, false) {
  }

  virtual void SetUp() {
    web_data_service_ = new WebDataServiceFake();
    db_thread_.Start();

    notification_service_ = new DBThreadNotificationService();
    notification_service_->Init();
  }

  virtual void TearDown() {
    service_.reset();
    notification_service_->TearDown();
    db_thread_.Stop();
    MessageLoop::current()->RunAllPending();
  }

  void StartSyncService() {
    if (!service_.get()) {
      service_.reset(new TestProfileSyncService(&factory_, &profile_, false));
      service_->AddObserver(&observer_);
      AutofillDataTypeController* data_type_controller =
          new AutofillDataTypeController(&factory_,
                                         &profile_,
                                         service_.get());

      EXPECT_CALL(factory_, CreateAutofillSyncComponents(_, _, _)).
          WillOnce(MakeAutofillSyncComponents(service_.get(),
                                              &web_database_,
                                              data_type_controller));
      EXPECT_CALL(factory_, CreateDataTypeManager(_)).
          WillOnce(MakeDataTypeManager());

      EXPECT_CALL(profile_, GetWebDataService(_)).
          WillOnce(Return(web_data_service_.get()));

      // State changes once for the backend init and once for startup done.
      EXPECT_CALL(observer_, OnStateChanged()).
          WillOnce(DoDefault()).
          WillOnce(QuitUIMessageLoop());
      service_->RegisterDataTypeController(data_type_controller);
      service_->Initialize();
      MessageLoop::current()->Run();
    }
  }

  void GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries) {
    sync_api::ReadTransaction trans(service_->backend()->GetUserShareHandle());
    int64 autofill_root_id =
        GetFakeServerTaggedNode(&trans, "google_chrome_autofill");
    if (autofill_root_id == sync_api::kInvalidId)
      return;

    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByIdLookup(autofill_root_id))
      return;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return;

      const sync_pb::AutofillSpecifics& autofill(
          child_node.GetAutofillSpecifics());
      AutofillKey key(UTF8ToUTF16(autofill.name()),
                      UTF8ToUTF16(autofill.value()));
      std::vector<base::Time> timestamps;
      int timestamps_count = autofill.usage_timestamp_size();
      for (int i = 0; i < timestamps_count; ++i) {
        timestamps.push_back(Time::FromInternalValue(
            autofill.usage_timestamp(i)));
      }
      entries->push_back(AutofillEntry(key, timestamps));
      child_id = child_node.GetSuccessorId();
    }
  }

  int64 GetFakeServerTaggedNode(sync_api::ReadTransaction* trans,
                                const std::string& tag) {
    std::wstring tag_wide;
    if (!UTF8ToWide(tag.c_str(), tag.length(), &tag_wide))
      return sync_api::kInvalidId;

    sync_api::ReadNode root(trans);
    root.InitByRootLookup();

    int64 last_child_id = sync_api::kInvalidId;
    for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) {
      sync_api::ReadNode child(trans);
      child.InitByIdLookup(id);
      last_child_id = id;
      if (tag_wide == child.GetTitle()) {
        return id;
      }
      id = child.GetSuccessorId();
    }

    return sync_api::kInvalidId;
  }

  void SetIdleChangeProcessorExpectations() {
    EXPECT_CALL(web_database_, RemoveFormElement(_, _)).Times(0);
    EXPECT_CALL(web_database_, GetAutofillTimestamps(_, _, _)).Times(0);
    EXPECT_CALL(web_database_, UpdateAutofillEntries(_)).Times(0);
  }

  static AutofillEntry MakeAutofillEntry(const char* name,
                                         const char* value,
                                         time_t timestamp) {
    std::vector<Time> timestamps;
    timestamps.push_back(Time::FromTimeT(timestamp));
    return AutofillEntry(
        AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
  }

  MessageLoopForUI message_loop_;
  ChromeThread ui_thread_;
  ChromeThread db_thread_;
  WaitableEvent done_event_;
  scoped_refptr<DBThreadNotificationService> notification_service_;

  scoped_ptr<TestProfileSyncService> service_;
  ProfileMock profile_;
  ProfileSyncFactoryMock factory_;
  ProfileSyncServiceObserverMock observer_;
  WebDatabaseMock web_database_;
  scoped_refptr<WebDataService> web_data_service_;
};

// TODO(sync): Test unrecoverable error during MA.

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_EmptyNativeEmptySync) {
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(0U, sync_entries.size());
}

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_HasNativeEmptySync) {
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  ASSERT_EQ(1U, entries.size());
  EXPECT_TRUE(entries[0] == sync_entries[0]);
}

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_HasNativeWithDuplicatesEmptySync) {
  // There is buggy autofill code that allows duplicate name/value
  // pairs to exist in the database with separate pair_ids.
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  entries.push_back(MakeAutofillEntry("dup", "", 2));
  entries.push_back(MakeAutofillEntry("dup", "", 3));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(2U, sync_entries.size());
}
<commit_msg>Fix autofill test hang The common TestProfileSyncService did some unexpected things with message loops, so use a custom version for this test.  Hopfully in a more testable future we won't need magic testing classes such as this.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"

using base::Time;
using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::UnrecoverableErrorHandler;
using sync_api::SyncManager;
using testing::_;
using testing::DoAll;
using testing::DoDefault;
using testing::Return;
using testing::SetArgumentPointee;

class TestingProfileSyncService : public ProfileSyncService {
 public:
  explicit TestingProfileSyncService(ProfileSyncFactory* factory,
                                     Profile* profile,
                                     bool bootstrap_sync_authentication)
      : ProfileSyncService(factory, profile, bootstrap_sync_authentication) {
    RegisterPreferences();
    SetSyncSetupCompleted();
  }
  virtual ~TestingProfileSyncService() {
  }

  virtual void InitializeBackend(bool delete_sync_data_folder) {
    browser_sync::TestHttpBridgeFactory* factory =
        new browser_sync::TestHttpBridgeFactory();
    browser_sync::TestHttpBridgeFactory* factory2 =
        new browser_sync::TestHttpBridgeFactory();
    backend()->InitializeForTestMode(L"testuser", factory, factory2,
        delete_sync_data_folder, browser_sync::kDefaultNotificationMethod);
  }

 private:
  // When testing under ChromiumOS, this method must not return an empty
  // value value in order for the profile sync service to start.
  virtual std::string GetLsidForAuthBootstraping() {
    return "foo";
  }
};

class TestAutofillModelAssociator
    : public TestModelAssociator<AutofillModelAssociator> {
 public:
  TestAutofillModelAssociator(ProfileSyncService* service,
                              WebDatabase* web_database,
                              UnrecoverableErrorHandler* error_handler)
      : TestModelAssociator<AutofillModelAssociator>(
          service, web_database, error_handler) {
  }
};

class WebDatabaseMock : public WebDatabase {
 public:
  MOCK_METHOD2(RemoveFormElement,
               bool(const string16& name, const string16& value));
  MOCK_METHOD1(GetAllAutofillEntries,
               bool(std::vector<AutofillEntry>* entries));
  MOCK_METHOD3(GetAutofillTimestamps,
               bool(const string16& name,
                    const string16& value,
                    std::vector<base::Time>* timestamps));
  MOCK_METHOD1(UpdateAutofillEntries,
               bool(const std::vector<AutofillEntry>& entries));
};

class ProfileMock : public TestingProfile {
 public:
  MOCK_METHOD1(GetWebDataService, WebDataService*(ServiceAccessType access));
};

class DBThreadNotificationService :
    public base::RefCountedThreadSafe<DBThreadNotificationService> {
 public:
  DBThreadNotificationService() : done_event_(false, false) {}

  void Init() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::InitTask));
    done_event_.Wait();
  }

  void TearDown() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::TearDownTask));
    done_event_.Wait();
  }

 private:
  friend class base::RefCountedThreadSafe<DBThreadNotificationService>;

  void InitTask() {
    service_.reset(new NotificationService());
    done_event_.Signal();
  }

  void TearDownTask() {
    service_.reset(NULL);
    done_event_.Signal();
  }

  WaitableEvent done_event_;
  scoped_ptr<NotificationService> service_;
};

class WebDataServiceFake : public WebDataService {
 public:
  virtual bool IsDatabaseLoaded() {
    return true;
  }

  // Note that we inject the WebDatabase through the
  // ProfileSyncFactory mock.
  virtual WebDatabase* GetDatabase() {
    return NULL;
  }
};

ACTION(QuitUIMessageLoop) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  MessageLoop::current()->Quit();
}

ACTION_P3(MakeAutofillSyncComponents, service, wd, dtc) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  AutofillModelAssociator* model_associator =
      new TestAutofillModelAssociator(service, wd, dtc);
  AutofillChangeProcessor* change_processor =
      new AutofillChangeProcessor(model_associator, wd, service);
  return ProfileSyncFactory::SyncComponents(model_associator, change_processor);
}

class ProfileSyncServiceAutofillTest : public testing::Test {
 protected:
  ProfileSyncServiceAutofillTest()
      : ui_thread_(ChromeThread::UI, &message_loop_),
        db_thread_(ChromeThread::DB),
        done_event_(false, false) {
  }

  virtual void SetUp() {
    web_data_service_ = new WebDataServiceFake();
    db_thread_.Start();

    notification_service_ = new DBThreadNotificationService();
    notification_service_->Init();
  }

  virtual void TearDown() {
    service_.reset();
    notification_service_->TearDown();
    db_thread_.Stop();
    MessageLoop::current()->RunAllPending();
  }

  void StartSyncService() {
    if (!service_.get()) {
      service_.reset(
          new TestingProfileSyncService(&factory_, &profile_, false));
      service_->AddObserver(&observer_);
      AutofillDataTypeController* data_type_controller =
          new AutofillDataTypeController(&factory_,
                                         &profile_,
                                         service_.get());

      EXPECT_CALL(factory_, CreateAutofillSyncComponents(_, _, _)).
          WillOnce(MakeAutofillSyncComponents(service_.get(),
                                              &web_database_,
                                              data_type_controller));
      EXPECT_CALL(factory_, CreateDataTypeManager(_)).
          WillOnce(MakeDataTypeManager());

      EXPECT_CALL(profile_, GetWebDataService(_)).
          WillOnce(Return(web_data_service_.get()));

      // State changes once for the backend init and once for startup done.
      EXPECT_CALL(observer_, OnStateChanged()).
          WillOnce(DoDefault()).
          WillOnce(QuitUIMessageLoop());
      service_->RegisterDataTypeController(data_type_controller);
      service_->Initialize();
      MessageLoop::current()->Run();
    }
  }

  void GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries) {
    sync_api::ReadTransaction trans(service_->backend()->GetUserShareHandle());
    int64 autofill_root_id =
        GetFakeServerTaggedNode(&trans, "google_chrome_autofill");
    if (autofill_root_id == sync_api::kInvalidId)
      return;

    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByIdLookup(autofill_root_id))
      return;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return;

      const sync_pb::AutofillSpecifics& autofill(
          child_node.GetAutofillSpecifics());
      AutofillKey key(UTF8ToUTF16(autofill.name()),
                      UTF8ToUTF16(autofill.value()));
      std::vector<base::Time> timestamps;
      int timestamps_count = autofill.usage_timestamp_size();
      for (int i = 0; i < timestamps_count; ++i) {
        timestamps.push_back(Time::FromInternalValue(
            autofill.usage_timestamp(i)));
      }
      entries->push_back(AutofillEntry(key, timestamps));
      child_id = child_node.GetSuccessorId();
    }
  }

  int64 GetFakeServerTaggedNode(sync_api::ReadTransaction* trans,
                                const std::string& tag) {
    std::wstring tag_wide;
    if (!UTF8ToWide(tag.c_str(), tag.length(), &tag_wide))
      return sync_api::kInvalidId;

    sync_api::ReadNode root(trans);
    root.InitByRootLookup();

    int64 last_child_id = sync_api::kInvalidId;
    for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) {
      sync_api::ReadNode child(trans);
      child.InitByIdLookup(id);
      last_child_id = id;
      if (tag_wide == child.GetTitle()) {
        return id;
      }
      id = child.GetSuccessorId();
    }

    return sync_api::kInvalidId;
  }

  void SetIdleChangeProcessorExpectations() {
    EXPECT_CALL(web_database_, RemoveFormElement(_, _)).Times(0);
    EXPECT_CALL(web_database_, GetAutofillTimestamps(_, _, _)).Times(0);
    EXPECT_CALL(web_database_, UpdateAutofillEntries(_)).Times(0);
  }

  static AutofillEntry MakeAutofillEntry(const char* name,
                                         const char* value,
                                         time_t timestamp) {
    std::vector<Time> timestamps;
    timestamps.push_back(Time::FromTimeT(timestamp));
    return AutofillEntry(
        AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
  }

  MessageLoopForUI message_loop_;
  ChromeThread ui_thread_;
  ChromeThread db_thread_;
  WaitableEvent done_event_;
  scoped_refptr<DBThreadNotificationService> notification_service_;

  scoped_ptr<TestingProfileSyncService> service_;
  ProfileMock profile_;
  ProfileSyncFactoryMock factory_;
  ProfileSyncServiceObserverMock observer_;
  WebDatabaseMock web_database_;
  scoped_refptr<WebDataService> web_data_service_;
};

// TODO(sync): Test unrecoverable error during MA.

TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(0U, sync_entries.size());
}

TEST_F(ProfileSyncServiceAutofillTest, HasNativeEmptySync) {
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  ASSERT_EQ(1U, entries.size());
  EXPECT_TRUE(entries[0] == sync_entries[0]);
}

TEST_F(ProfileSyncServiceAutofillTest, HasNativeWithDuplicatesEmptySync) {
  // There is buggy autofill code that allows duplicate name/value
  // pairs to exist in the database with separate pair_ids.
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  entries.push_back(MakeAutofillEntry("dup", "", 2));
  entries.push_back(MakeAutofillEntry("dup", "", 3));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(2U, sync_entries.size());
}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/experimental/delegates/hexagon/hexagon_nn/hexagon_nn_init.h"

#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "remote.h"  // NOLINT
#include "rpcmem.h"  // NOLINT
#include "tensorflow/lite/experimental/delegates/hexagon/hexagon_nn/soc_model.h"

#ifdef __cplusplus
extern "C" {
#endif
// Version 1.14
static const int kHexagonNNVersion = 136193;
#pragma weak remote_handle_control  // Declare it as a weak symbol
void hexagon_nn_global_init() {
  rpcmem_init();
  // Non-domains QoS invocation
  struct remote_rpc_control_latency data;
  data.enable = 1;
  if (remote_handle_control) {  // Check if API is available before invoking
    remote_handle_control(DSPRPC_CONTROL_LATENCY, (void*)&data, sizeof(data));
  }
}

void hexagon_nn_global_teardown() { rpcmem_deinit(); }

bool hexagon_nn_is_device_supported() {
  return tflite::delegates::getsoc_model().mode != UNSPECIFIED_MODE;
}

int hexagon_nn_hexagon_interface_version() { return kHexagonNNVersion; }

#ifdef __cplusplus
}
#endif
<commit_msg>Internal code change<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/experimental/delegates/hexagon/hexagon_nn/hexagon_nn_init.h"

#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "remote.h"  // NOLINT
#include "rpcmem.h"  // NOLINT
#include "tensorflow/lite/experimental/delegates/hexagon/hexagon_nn/soc_model.h"

#ifdef __cplusplus
extern "C" {
#endif
// Version 1.17
static const int kHexagonNNVersion = 136960;
#pragma weak remote_handle_control  // Declare it as a weak symbol
void hexagon_nn_global_init() {
  rpcmem_init();
  // Non-domains QoS invocation
  struct remote_rpc_control_latency data;
  data.enable = 1;
  if (remote_handle_control) {  // Check if API is available before invoking
    remote_handle_control(DSPRPC_CONTROL_LATENCY, (void*)&data, sizeof(data));
  }
}

void hexagon_nn_global_teardown() { rpcmem_deinit(); }

bool hexagon_nn_is_device_supported() {
  return tflite::delegates::getsoc_model().mode != UNSPECIFIED_MODE;
}

int hexagon_nn_hexagon_interface_version() { return kHexagonNNVersion; }

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h"

#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
#include "grit/ui_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/display.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/views/border.h"
#include "ui/views/widget/widget.h"

using WebKit::WebAutofillClient;

namespace {

const SkColor kBorderColor = SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE);
const SkColor kHoveredBackgroundColor = SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD);
const SkColor kItemTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
const SkColor kPopupBackground = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
const SkColor kValueTextColor = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);

}  // namespace

AutofillPopupViewViews::AutofillPopupViewViews(
    AutofillPopupController* controller)
    : controller_(controller),
      observing_widget_(NULL) {}

AutofillPopupViewViews::~AutofillPopupViewViews() {
  if (observing_widget_)
    observing_widget_->RemoveObserver(this);

  controller_->ViewDestroyed();
}

void AutofillPopupViewViews::Hide() {
  if (GetWidget()) {
    // This deletes |this|.
    GetWidget()->Close();
  } else {
    delete this;
  }
}

void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) {
  canvas->DrawColor(kPopupBackground);
  OnPaintBorder(canvas);

  for (size_t i = 0; i < controller_->names().size(); ++i) {
    gfx::Rect line_rect = controller_->GetRowBounds(i);

    if (controller_->identifiers()[i] ==
            WebAutofillClient::MenuItemIDSeparator) {
      canvas->DrawRect(line_rect, kItemTextColor);
    } else {
      DrawAutofillEntry(canvas, i, line_rect);
    }
  }
}

void AutofillPopupViewViews::OnMouseCaptureLost() {
  controller_->MouseExitedPopup();
}

bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) {
  if (HitTestPoint(gfx::Point(event.x(), event.y()))) {
    controller_->MouseHovered(event.x(), event.y());

    // We must return true in order to get future OnMouseDragged and
    // OnMouseReleased events.
    return true;
  }

  // If we move off of the popup, we lose the selection.
  controller_->MouseExitedPopup();
  return false;
}

void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) {
  controller_->MouseExitedPopup();
}

void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) {
  controller_->MouseHovered(event.x(), event.y());
}

bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) {
  // We must return true in order to get the OnMouseReleased event later.
  return true;
}

void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) {
  // We only care about the left click.
  if (event.IsOnlyLeftMouseButton() &&
      HitTestPoint(gfx::Point(event.x(), event.y())))
    controller_->MouseClicked(event.x(), event.y());
}

void AutofillPopupViewViews::OnWidgetBoundsChanged(
    views::Widget* widget,
    const gfx::Rect& new_bounds) {
  Hide();
}

void AutofillPopupViewViews::Show() {
  if (!GetWidget()) {
    // The widget is destroyed by the corresponding NativeWidget, so we use
    // a weak pointer to hold the reference and don't have to worry about
    // deletion.
    views::Widget* widget = new views::Widget;
    views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
    params.delegate = this;
    params.can_activate = false;
    params.transparent = true;
    params.parent = controller_->container_view();
    widget->Init(params);
    widget->SetContentsView(this);
    widget->Show();

    // Allow the popup to appear anywhere on the screen, since it may need
    // to go beyond the bounds of the window.
    // TODO(csharp): allow the popup to still appear on the border of
    // two screens.
    widget->SetBounds(gfx::Rect(GetScreenSize()));

    // Setup an observer to check for when the browser moves or changes size,
    // since the popup should always be hidden in those cases.
    observing_widget_ = views::Widget::GetTopLevelWidgetForNativeView(
        controller_->container_view());
    observing_widget_->AddObserver(this);
  }

  set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor));

  SetInitialBounds();
  UpdateBoundsAndRedrawPopup();
}

void AutofillPopupViewViews::InvalidateRow(size_t row) {
  SchedulePaintInRect(controller_->GetRowBounds(row));
}

void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() {
  SetBoundsRect(controller_->popup_bounds());
  SchedulePaintInRect(controller_->popup_bounds());
}

void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas,
                                               int index,
                                               const gfx::Rect& entry_rect) {
  // TODO(csharp): support RTL

  if (controller_->selected_line() == index)
    canvas->FillRect(entry_rect, kHoveredBackgroundColor);

  canvas->DrawStringInt(
      controller_->names()[index],
      controller_->name_font(),
      kValueTextColor,
      kEndPadding,
      entry_rect.y(),
      canvas->GetStringWidth(controller_->names()[index],
                             controller_->name_font()),
      entry_rect.height(),
      gfx::Canvas::TEXT_ALIGN_CENTER);

  // Use this to figure out where all the other Autofill items should be placed.
  int x_align_left = entry_rect.width() - kEndPadding;

  // Draw the delete icon, if one is needed.
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  int row_height = controller_->GetRowBounds(index).height();
  if (controller_->CanDelete(index)) {
    x_align_left -= kDeleteIconWidth;

    // TODO(csharp): Create a custom resource for the delete icon.
    // http://crbug.com/131801
    canvas->DrawImageInt(
        *rb.GetImageSkiaNamed(IDR_CLOSE_BAR),
        x_align_left,
        entry_rect.y() + (row_height - kDeleteIconHeight) / 2);

    x_align_left -= kIconPadding;
  }

  // Draw the Autofill icon, if one exists
  if (!controller_->icons()[index].empty()) {
    int icon = controller_->GetIconResourceID(controller_->icons()[index]);
    DCHECK_NE(-1, icon);
    int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2;

    x_align_left -= kAutofillIconWidth;

    canvas->DrawImageInt(*rb.GetImageSkiaNamed(icon), x_align_left, icon_y);

    x_align_left -= kIconPadding;
  }

  // Draw the name text.
  x_align_left -= canvas->GetStringWidth(controller_->subtexts()[index],
                                         controller_->subtext_font());

  canvas->DrawStringInt(
      controller_->subtexts()[index],
      controller_->subtext_font(),
      kItemTextColor,
      x_align_left + kEndPadding,
      entry_rect.y(),
      canvas->GetStringWidth(controller_->subtexts()[index],
                             controller_->subtext_font()),
      entry_rect.height(),
      gfx::Canvas::TEXT_ALIGN_CENTER);
}

void AutofillPopupViewViews::SetInitialBounds() {
  int bottom_of_field = controller_->element_bounds().bottom();
  int popup_height = controller_->GetPopupRequiredHeight();

  // Find the correct top position of the popup so that it doesn't go off
  // the screen.
  int top_of_popup = 0;
  if (GetScreenSize().height() < bottom_of_field + popup_height) {
    // The popup must appear above the field.
    top_of_popup = controller_->element_bounds().y() - popup_height;
  } else {
    // The popup can appear below the field.
    top_of_popup = bottom_of_field;
  }

  controller_->SetPopupBounds(gfx::Rect(
      controller_->element_bounds().x(),
      top_of_popup,
      controller_->GetPopupRequiredWidth(),
      popup_height));
}

gfx::Size AutofillPopupViewViews::GetScreenSize() {
  gfx::Screen* screen =
      gfx::Screen::GetScreenFor(controller_->container_view());
  gfx::Display display =
      screen->GetDisplayNearestPoint(controller_->element_bounds().origin());

  return display.GetSizeInPixel();
}

AutofillPopupView* AutofillPopupView::Create(
    AutofillPopupController* controller) {
  return new AutofillPopupViewViews(controller);
}
<commit_msg>make views autofill popup dismiss when user clicks outside of its bounds<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h"

#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
#include "grit/ui_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/display.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/views/border.h"
#include "ui/views/widget/widget.h"

using WebKit::WebAutofillClient;

namespace {

const SkColor kBorderColor = SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE);
const SkColor kHoveredBackgroundColor = SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD);
const SkColor kItemTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
const SkColor kPopupBackground = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
const SkColor kValueTextColor = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);

}  // namespace

AutofillPopupViewViews::AutofillPopupViewViews(
    AutofillPopupController* controller)
    : controller_(controller),
      observing_widget_(NULL) {}

AutofillPopupViewViews::~AutofillPopupViewViews() {
  if (observing_widget_)
    observing_widget_->RemoveObserver(this);

  controller_->ViewDestroyed();
}

void AutofillPopupViewViews::Hide() {
  if (GetWidget()) {
    // This deletes |this|.
    GetWidget()->Close();
  } else {
    delete this;
  }
}

void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) {
  canvas->DrawColor(kPopupBackground);
  OnPaintBorder(canvas);

  for (size_t i = 0; i < controller_->names().size(); ++i) {
    gfx::Rect line_rect = controller_->GetRowBounds(i);

    if (controller_->identifiers()[i] ==
            WebAutofillClient::MenuItemIDSeparator) {
      canvas->DrawRect(line_rect, kItemTextColor);
    } else {
      DrawAutofillEntry(canvas, i, line_rect);
    }
  }
}

void AutofillPopupViewViews::OnMouseCaptureLost() {
  controller_->MouseExitedPopup();
}

bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) {
  if (HitTestPoint(gfx::Point(event.x(), event.y()))) {
    controller_->MouseHovered(event.x(), event.y());

    // We must return true in order to get future OnMouseDragged and
    // OnMouseReleased events.
    return true;
  }

  // If we move off of the popup, we lose the selection.
  controller_->MouseExitedPopup();
  return false;
}

void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) {
  controller_->MouseExitedPopup();
}

void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) {
  controller_->MouseHovered(event.x(), event.y());
}

bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) {
  // We must return true in order to get the OnMouseReleased event later.
  return true;
}

void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) {
  // We only care about the left click.
  if (event.IsOnlyLeftMouseButton() &&
      HitTestPoint(gfx::Point(event.x(), event.y())))
    controller_->MouseClicked(event.x(), event.y());
}

void AutofillPopupViewViews::OnWidgetBoundsChanged(
    views::Widget* widget,
    const gfx::Rect& new_bounds) {
  Hide();
}

void AutofillPopupViewViews::Show() {
  if (!GetWidget()) {
    // The widget is destroyed by the corresponding NativeWidget, so we use
    // a weak pointer to hold the reference and don't have to worry about
    // deletion.
    views::Widget* widget = new views::Widget;
    views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
    params.delegate = this;
    params.transparent = true;
    params.parent = controller_->container_view();
    widget->Init(params);
    widget->SetContentsView(this);
    widget->SetBounds(controller_->popup_bounds());
    widget->Show();

    // Setup an observer to check for when the browser moves or changes size,
    // since the popup should always be hidden in those cases.
    observing_widget_ = views::Widget::GetTopLevelWidgetForNativeView(
        controller_->container_view());
    observing_widget_->AddObserver(this);
  }

  set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor));

  SetInitialBounds();
  UpdateBoundsAndRedrawPopup();
}

void AutofillPopupViewViews::InvalidateRow(size_t row) {
  SchedulePaintInRect(controller_->GetRowBounds(row));
}

void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() {
  GetWidget()->SetBounds(controller_->popup_bounds());
  SchedulePaint();
}

void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas,
                                               int index,
                                               const gfx::Rect& entry_rect) {
  // TODO(csharp): support RTL

  if (controller_->selected_line() == index)
    canvas->FillRect(entry_rect, kHoveredBackgroundColor);

  canvas->DrawStringInt(
      controller_->names()[index],
      controller_->name_font(),
      kValueTextColor,
      kEndPadding,
      entry_rect.y(),
      canvas->GetStringWidth(controller_->names()[index],
                             controller_->name_font()),
      entry_rect.height(),
      gfx::Canvas::TEXT_ALIGN_CENTER);

  // Use this to figure out where all the other Autofill items should be placed.
  int x_align_left = entry_rect.width() - kEndPadding;

  // Draw the delete icon, if one is needed.
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  int row_height = controller_->GetRowBounds(index).height();
  if (controller_->CanDelete(index)) {
    x_align_left -= kDeleteIconWidth;

    // TODO(csharp): Create a custom resource for the delete icon.
    // http://crbug.com/131801
    canvas->DrawImageInt(
        *rb.GetImageSkiaNamed(IDR_CLOSE_BAR),
        x_align_left,
        entry_rect.y() + (row_height - kDeleteIconHeight) / 2);

    x_align_left -= kIconPadding;
  }

  // Draw the Autofill icon, if one exists
  if (!controller_->icons()[index].empty()) {
    int icon = controller_->GetIconResourceID(controller_->icons()[index]);
    DCHECK_NE(-1, icon);
    int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2;

    x_align_left -= kAutofillIconWidth;

    canvas->DrawImageInt(*rb.GetImageSkiaNamed(icon), x_align_left, icon_y);

    x_align_left -= kIconPadding;
  }

  // Draw the name text.
  x_align_left -= canvas->GetStringWidth(controller_->subtexts()[index],
                                         controller_->subtext_font());

  canvas->DrawStringInt(
      controller_->subtexts()[index],
      controller_->subtext_font(),
      kItemTextColor,
      x_align_left + kEndPadding,
      entry_rect.y(),
      canvas->GetStringWidth(controller_->subtexts()[index],
                             controller_->subtext_font()),
      entry_rect.height(),
      gfx::Canvas::TEXT_ALIGN_CENTER);
}

void AutofillPopupViewViews::SetInitialBounds() {
  int bottom_of_field = controller_->element_bounds().bottom();
  int popup_height = controller_->GetPopupRequiredHeight();

  // Find the correct top position of the popup so that it doesn't go off
  // the screen.
  int top_of_popup = 0;
  if (GetScreenSize().height() < bottom_of_field + popup_height) {
    // The popup must appear above the field.
    top_of_popup = controller_->element_bounds().y() - popup_height;
  } else {
    // The popup can appear below the field.
    top_of_popup = bottom_of_field;
  }

  controller_->SetPopupBounds(gfx::Rect(
      controller_->element_bounds().x(),
      top_of_popup,
      controller_->GetPopupRequiredWidth(),
      popup_height));
}

gfx::Size AutofillPopupViewViews::GetScreenSize() {
  gfx::Screen* screen =
      gfx::Screen::GetScreenFor(controller_->container_view());
  gfx::Display display =
      screen->GetDisplayNearestPoint(controller_->element_bounds().origin());

  return display.GetSizeInPixel();
}

AutofillPopupView* AutofillPopupView::Create(
    AutofillPopupController* controller) {
  return new AutofillPopupViewViews(controller);
}
<|endoftext|>


<commit_before>#pragma once

#include "Constants.hpp"
#include "Geometry2d/Point.hpp"
#include "time.hpp"

#include <cmath>
#include <deque>
#include <QString>
#include <stdexcept>
#include <stdint.h>
#include <sys/time.h>
#include <typeinfo>
#include <vector>

const static bool THROW_DEBUG_EXCEPTIONS = true;

static inline void debugThrow(const std::string &string) {
	if (THROW_DEBUG_EXCEPTIONS) {
		throw std::runtime_error(string);
	}
}

static inline void debugThrow(const std::exception &exception) {
	if (THROW_DEBUG_EXCEPTIONS) {
		throw exception;
	}
}

/**
 * @brief Restricts the given angle to be between pi and -pi
 *
 * @param a An angle in radians
 * @return An equivalent angle in radians restricted to [-pi, pi]
 */
static inline float fixAngleRadians(float a)
{
	a = remainder(a, 2*M_PI);
	while (a < -M_PI) a += 2.0*M_PI;
	while (a > M_PI) a -= 2.0*M_PI;
	return a;
}

/** Checks whether or not the given ball is in the defense area. */
static inline bool ballIsInGoalieBox(Geometry2d::Point point) {
	if (std::abs(point.x) < Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f) // Ball is in center (rectangular) portion of defensive bubble
	{
		return point.y > 0 && point.y < Field_Dimensions::Current_Dimensions.ArcRadius();
	} else if (std::abs(point.x) < (Field_Dimensions::Current_Dimensions.ArcRadius() + Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f)) // Ball is in one of the side (arc) portions of defensive bubble
	{
		double adjusted_x = std::abs(point.x) - (Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f);
		double max_y = sqrt( (Field_Dimensions::Current_Dimensions.ArcRadius() * Field_Dimensions::Current_Dimensions.ArcRadius()) - (adjusted_x * adjusted_x));
		return point.y > 0 && point.y <= max_y;
	}
	return false;
}

static Geometry2d::Point fromOursToTheirs(Geometry2d::Point &pt) {
	Geometry2d::Point c;
	c.y = Field_Dimensions::Current_Dimensions.Length() - pt.y;
	c.x = -pt.x;

	return c;
}

static bool ballIsInTheirGoalieBox(Geometry2d::Point &pt) {
	Geometry2d::Point converted = fromOursToTheirs(pt);
	return ballIsInGoalieBox(converted);
}

/** Returns @value if it is in bounds, otherwise returns the bound it is closest to */
template<class T>
float clamp(T value, T min, T max)
{
	if (value > max)
	{
		return max;
	}
	else if (value < min)
	{
		return min;
	}
	return value;
}

// Removes all entries in a std::map which associate to the given value.
template<class Map_Type, class Data_Type>
void map_remove(Map_Type &map, Data_Type &value)
{
	typename Map_Type::iterator i = map.begin();
	while (i != map.end())
	{
		typename Map_Type::iterator next = i;
		++next;

		if (i->second == value)
		{
			map.erase(i);
		}

		i = next;
	}
}

// If <key> exists in <map>, returns map[key].
// If not, returns 0.
template<typename Map>
typename Map::mapped_type map_lookup(const Map &map, typename Map::key_type key)
{
	typename Map::const_iterator i = map.find(key);
	if (i != map.end())
	{
		return i->second;
	} else {
		return 0;
	}
}

/**
 * A basic FIR filter of variable type with float coeffs
 *
 * Note, coefficients will be normalized so that inputs
 * will always be scaled appropriately
 */
template<typename T>
class FIRFilter {
public:
	typedef std::vector<float> Coeffs;

	FIRFilter(const T& zero, size_t nrTaps) : _zero(zero) {
		if (nrTaps == 0)
			throw std::invalid_argument("FIR Filter: number of taps must be greater than zero");

		// initialize
		_taps.assign(nrTaps, _zero);
		_coeffs.assign(nrTaps, 0.0f);
		_coeffs[0] = 1.0;
	}

	T filter(const T& x) {
		_taps.push_front(x);
		_taps.pop_back();

		T y = _zero;
		for (size_t i = 0; i<_taps.size(); ++i)
			y += _taps.at(i) * _coeffs.at(i);

		return y;
	}

	/** reinitializes the coeffs and taps to new values */
	void setCoeffs(const Coeffs& coeffs) {
		size_t nrTaps = coeffs.size();
		if (nrTaps == 0)
			throw std::invalid_argument("FIR Filter: number of coeffs must be greater than zero");

		_taps.assign(nrTaps, _zero);
		_coeffs.assign(nrTaps, 0.0);

		// find the normalizer
		float normalizer = 0.0;
		for (size_t i = 0; i<coeffs.size(); ++i)
			normalizer += coeffs.at(i);

		// set the normalized coefficients
		for (size_t i=0; i<coeffs.size(); ++i)
			_coeffs[i] = coeffs.at(i) / normalizer;
	}

protected:
	T _zero;
	std::deque<T> _taps;
	Coeffs _coeffs;
};

// An output iterator which throws an exception when it's used.
// This is used for example to determine if the output of set_difference would be non-empty without
// calculating all of it.
template<typename T>
class ExceptionIterator: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
	ExceptionIterator &operator=(const T &value)
	{
		throw std::exception();
	}

	ExceptionIterator &operator*()
	{
		return *this;
	}

	ExceptionIterator &operator++()
	{
		return *this;
	}

	ExceptionIterator &operator++(int)
	{
		return *this;
	}
};

// Sets str to the name of a class.
// Use it like this:
//		Object *obj = new Object();
//		QString name = typeName(typeid(*obj));
// The returned name is in the usual C++ format: "Namespace::Namespace::Class"
QString typeName(const std::type_info &info);

// Like typeName, but only returns the final class name part.
QString className(const std::type_info &info);
<commit_msg>Fix the debugThrow Util<commit_after>#pragma once

#include "Constants.hpp"
#include "Geometry2d/Point.hpp"
#include "time.hpp"

#include <cmath>
#include <deque>
#include <QString>
#include <stdexcept>
#include <stdint.h>
#include <sys/time.h>
#include <typeinfo>
#include <vector>

const static bool THROW_DEBUG_EXCEPTIONS = true;

static inline void debugThrow(const std::string &string) {
	if (THROW_DEBUG_EXCEPTIONS) {
		throw std::runtime_error(string);
	}
}

template <class exception>
static inline void debugThrow(const exception &e) {
	if (THROW_DEBUG_EXCEPTIONS) {
		throw e;
	}
}

/**
 * @brief Restricts the given angle to be between pi and -pi
 *
 * @param a An angle in radians
 * @return An equivalent angle in radians restricted to [-pi, pi]
 */
static inline float fixAngleRadians(float a)
{
	a = remainder(a, 2*M_PI);
	while (a < -M_PI) a += 2.0*M_PI;
	while (a > M_PI) a -= 2.0*M_PI;
	return a;
}

/** Checks whether or not the given ball is in the defense area. */
static inline bool ballIsInGoalieBox(Geometry2d::Point point) {
	if (std::abs(point.x) < Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f) // Ball is in center (rectangular) portion of defensive bubble
	{
		return point.y > 0 && point.y < Field_Dimensions::Current_Dimensions.ArcRadius();
	} else if (std::abs(point.x) < (Field_Dimensions::Current_Dimensions.ArcRadius() + Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f)) // Ball is in one of the side (arc) portions of defensive bubble
	{
		double adjusted_x = std::abs(point.x) - (Field_Dimensions::Current_Dimensions.GoalFlat() / 2.0f);
		double max_y = sqrt( (Field_Dimensions::Current_Dimensions.ArcRadius() * Field_Dimensions::Current_Dimensions.ArcRadius()) - (adjusted_x * adjusted_x));
		return point.y > 0 && point.y <= max_y;
	}
	return false;
}

static Geometry2d::Point fromOursToTheirs(Geometry2d::Point &pt) {
	Geometry2d::Point c;
	c.y = Field_Dimensions::Current_Dimensions.Length() - pt.y;
	c.x = -pt.x;

	return c;
}

static bool ballIsInTheirGoalieBox(Geometry2d::Point &pt) {
	Geometry2d::Point converted = fromOursToTheirs(pt);
	return ballIsInGoalieBox(converted);
}

/** Returns @value if it is in bounds, otherwise returns the bound it is closest to */
template<class T>
float clamp(T value, T min, T max)
{
	if (value > max)
	{
		return max;
	}
	else if (value < min)
	{
		return min;
	}
	return value;
}

// Removes all entries in a std::map which associate to the given value.
template<class Map_Type, class Data_Type>
void map_remove(Map_Type &map, Data_Type &value)
{
	typename Map_Type::iterator i = map.begin();
	while (i != map.end())
	{
		typename Map_Type::iterator next = i;
		++next;

		if (i->second == value)
		{
			map.erase(i);
		}

		i = next;
	}
}

// If <key> exists in <map>, returns map[key].
// If not, returns 0.
template<typename Map>
typename Map::mapped_type map_lookup(const Map &map, typename Map::key_type key)
{
	typename Map::const_iterator i = map.find(key);
	if (i != map.end())
	{
		return i->second;
	} else {
		return 0;
	}
}

/**
 * A basic FIR filter of variable type with float coeffs
 *
 * Note, coefficients will be normalized so that inputs
 * will always be scaled appropriately
 */
template<typename T>
class FIRFilter {
public:
	typedef std::vector<float> Coeffs;

	FIRFilter(const T& zero, size_t nrTaps) : _zero(zero) {
		if (nrTaps == 0)
			throw std::invalid_argument("FIR Filter: number of taps must be greater than zero");

		// initialize
		_taps.assign(nrTaps, _zero);
		_coeffs.assign(nrTaps, 0.0f);
		_coeffs[0] = 1.0;
	}

	T filter(const T& x) {
		_taps.push_front(x);
		_taps.pop_back();

		T y = _zero;
		for (size_t i = 0; i<_taps.size(); ++i)
			y += _taps.at(i) * _coeffs.at(i);

		return y;
	}

	/** reinitializes the coeffs and taps to new values */
	void setCoeffs(const Coeffs& coeffs) {
		size_t nrTaps = coeffs.size();
		if (nrTaps == 0)
			throw std::invalid_argument("FIR Filter: number of coeffs must be greater than zero");

		_taps.assign(nrTaps, _zero);
		_coeffs.assign(nrTaps, 0.0);

		// find the normalizer
		float normalizer = 0.0;
		for (size_t i = 0; i<coeffs.size(); ++i)
			normalizer += coeffs.at(i);

		// set the normalized coefficients
		for (size_t i=0; i<coeffs.size(); ++i)
			_coeffs[i] = coeffs.at(i) / normalizer;
	}

protected:
	T _zero;
	std::deque<T> _taps;
	Coeffs _coeffs;
};

// An output iterator which throws an exception when it's used.
// This is used for example to determine if the output of set_difference would be non-empty without
// calculating all of it.
template<typename T>
class ExceptionIterator: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
	ExceptionIterator &operator=(const T &value)
	{
		throw std::exception();
	}

	ExceptionIterator &operator*()
	{
		return *this;
	}

	ExceptionIterator &operator++()
	{
		return *this;
	}

	ExceptionIterator &operator++(int)
	{
		return *this;
	}
};

// Sets str to the name of a class.
// Use it like this:
//		Object *obj = new Object();
//		QString name = typeName(typeid(*obj));
// The returned name is in the usual C++ format: "Namespace::Namespace::Class"
QString typeName(const std::type_info &info);

// Like typeName, but only returns the final class name part.
QString className(const std::type_info &info);
<|endoftext|>


<commit_before>
#include <iostream>

#include "SDL2/SDL.h"

#include "sdl/error.h"
#include "sdl/window.h"
#include "sdl/renderer.h"
#include "sdl/texture.h"
#include "sdl/sdl_init.h"
#include "sdl/color.h"
#include "sdl/timer.h"

#include "phys/system.h"
#include "phys/basic_material.h"
#include "phys/detector.h"
#include "phys/fuel_material.h"
#include "phys/moderator_material.h"
#include "phys/absorb_material.h"
#include "phys/stream_src.h"

#include "draw/sys_view.h"

using sdl::Color;

const int neutron_burst = 1000;

int main(int argc, char** argv) {
  std::ranlux48_base rand_gen;
  std::uniform_real_distribution<> uniform01;

  try {
    sdl::SDLinit init(SDL_INIT_EVERYTHING);

    // create window and renderer
    int w = 850;
    int h = 650;
    sdl::Window win("Reactor", w, h, 0);
    win.Center();
    win.Show();
    sdl::Renderer ren(win, SDL_RENDERER_ACCELERATED);

    // create material geometry
    phys::BasicMaterial reflector1{0, 0, .1, 1, 0};
    phys::Object::Rect r1{w/2 - 40, h/2 - 40, 120, 120};
    reflector1.Init(r1, sdl::Color::white());
    phys::BasicMaterial reflector2(&reflector1);
    phys::BasicMaterial reflector3(&reflector1);
    phys::BasicMaterial reflector4(&reflector1);

    phys::Absorber absorber1{.1};
    phys::Object::Rect r2{w/2 - 130, h/2 - 40, 80, 80};
    absorber1.Init(r2, sdl::Color::blue());
    phys::Absorber absorber2(&absorber1);
    phys::Absorber absorber3(&absorber1);
    phys::Absorber absorber4(&absorber1);

    phys::BasicMaterial moderator1{0, 0, .03, .3, 0};
    phys::Object::Rect r3{w/2 + 50, h/2 - 40, 80, 80};
    moderator1.Init(r3, sdl::Color::green());
    phys::BasicMaterial moderator2(&moderator1);
    phys::BasicMaterial moderator3(&moderator1);
    phys::BasicMaterial moderator4(&moderator1);

    phys::Moderator voidmoderator1(.03, .3, 200);
    phys::Object::Rect r3b{w/2 + 130, h/2 - 40, 60, 60};
    voidmoderator1.Init(r3b, sdl::Color::lime());

    phys::Fuel fuel1(0, 0.070, 2);
    phys::Object::Rect r4{w/2 - 20, h/2 + 50, 40, 40};
    fuel1.Init(r4, sdl::Color::purple());
    phys::Fuel fuel2(&fuel1);
    phys::Fuel fuel3(&fuel1);
    phys::Fuel fuel4(&fuel1);
    phys::Fuel fuel5(&fuel1);
    phys::Fuel fuel6(&fuel1);
    phys::Fuel fuel7(&fuel1);
    phys::Fuel fuel8(&fuel1);
    phys::Fuel fuel9(&fuel1);

    phys::Object::Rect r5{w/2 + 130, h/2 + 140, 100, 100};
    phys::Detector detector1;
    detector1.Init(r5, sdl::Color::yellow(128));
    phys::Detector detector2(&detector1);

    phys::Object::Rect r6{w/2 + 80, h/2 + 80, 50, 50};
    phys::Detector detector3;
    detector3.Init(r6, sdl::Color::yellow(128));
    phys::Detector detector4(&detector3);

    phys::StreamSource stream1;
    phys::Object::Rect r7{w/2 + 130, h/2 - 40, 40, 40};
    stream1.Init(r7, sdl::Color::olive());

    // create system and a view for drawing it
    phys::System sys(w, h);
    sys.AddToolbar();
    phys::Object::Rect tb_r = sys.toolbar().rect();

    //add fuel item inside toolbar
    phys::Fuel fuel(0, 0.070, 2);
    phys::Object::Rect fr{tb_r.x+tb_r.w/2-20,tb_r.y+(int)((double)tb_r.h*.25)-20,40,40};
    fuel.Init(fr, sdl::Color::purple());
    sys.AddObject(&fuel);

    phys::BasicMaterial reflector{0, 0, .1, 1, 0};
    phys::Object::Rect rr{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.6)-40,80,80};
    reflector.Init(rr, sdl::Color::white());
    sys.AddObject(&reflector);

    phys::Absorber absorber{.1};
    phys::Object::Rect ar{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.75)-40,80,80};
    absorber.Init(ar, sdl::Color::blue());
    sys.AddObject(&absorber);

    phys::BasicMaterial moderator{0, 0, .03, .3, 0};
    phys::Object::Rect mr{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.9)-40,80,80};
    moderator.Init(mr, sdl::Color::green());
    sys.AddObject(&moderator);

    stream1.sys(&sys);

    draw::SysView view(&sys, &ren);

    // start up the main loop
    SDL_Event ev;
    sdl::Timer timer;
    timer.Start();
    bool done = false;
    bool dragging = false;
    phys::Object* dragged = nullptr;
    phys::Object* clicked = nullptr;
    while(!done) {
      // process events
      while(SDL_PollEvent(&ev)) {
        if (ev.type == SDL_QUIT) {
          done = true;
        } else if (ev.type == SDL_MOUSEBUTTONDOWN &&
                   ev.button.button == SDL_BUTTON_RIGHT) {
          clicked = sys.ObjectFor(ev.button.x, ev.button.y);
          if (clicked->OnClick(ev.button.x, ev.button.y))
            continue;
          // create some neutrons
          phys::Neutron::Pop ns;
          for (int i = 0; i < neutron_burst; ++i) {
            double theta = uniform01(rand_gen) * 2 * 3.141592654;
            int vx = std::cos(theta) * phys::Neutron::kNomSpeed;
            int vy = std::sin(theta) * phys::Neutron::kNomSpeed;
            ns.push_back(phys::Neutron(ev.button.x, ev.button.y, vx, vy));
          }
          sys.AddNeutrons(ns);
        } else if (ev.type == SDL_MOUSEBUTTONDOWN &&
                   ev.button.button == SDL_BUTTON_LEFT) {
          dragged = sys.ObjectFor(ev.button.x, ev.button.y);
	  if(dragged->isToolbar())
	    continue;
	  if(sys.inToolbar(dragged) && !dragged->detector())
	    {
	      phys::Object* temp = dragged->clone();
	      sys.AddObject(&(*temp));
	    }
          sys.MoveTop(dragged);
          dragging = true;
        } else if (ev.type == SDL_KEYDOWN) {
          if (dragged == nullptr) {
            continue;
          }
          if (ev.key.keysym.sym == SDLK_DOWN) {
            dragged->Shift(0, 5);
          } else if (ev.key.keysym.sym == SDLK_UP) {
            dragged->Shift(0, -5);
          } else if (ev.key.keysym.sym == SDLK_LEFT) {
            dragged->Shift(-5, 0);
          } else if (ev.key.keysym.sym == SDLK_RIGHT) {
            dragged->Shift(5, 0);
          }
        } else if (ev.type == SDL_MOUSEBUTTONUP && ev.button.button == SDL_BUTTON_LEFT) {
          dragging = false;
        } else if (ev.type == SDL_MOUSEMOTION && dragging) {
          dragged->Shift(ev.motion.xrel, ev.motion.yrel);
        }
      }

      double dt = (double)timer.Mark();
      sys.Tick(dt / 1000);
      view.Render(((double)1000) / dt);
    }

    return 0;
  } catch (sdl::FatalErr err) {
    std::cout << "ERROR: " << err.what() << "\n";
    return 1;
  }
}

<commit_msg>Moved fuel object down a bit in the toolbar.<commit_after>
#include <iostream>

#include "SDL2/SDL.h"

#include "sdl/error.h"
#include "sdl/window.h"
#include "sdl/renderer.h"
#include "sdl/texture.h"
#include "sdl/sdl_init.h"
#include "sdl/color.h"
#include "sdl/timer.h"

#include "phys/system.h"
#include "phys/basic_material.h"
#include "phys/detector.h"
#include "phys/fuel_material.h"
#include "phys/moderator_material.h"
#include "phys/absorb_material.h"
#include "phys/stream_src.h"

#include "draw/sys_view.h"

using sdl::Color;

const int neutron_burst = 1000;

int main(int argc, char** argv) {
  std::ranlux48_base rand_gen;
  std::uniform_real_distribution<> uniform01;

  try {
    sdl::SDLinit init(SDL_INIT_EVERYTHING);

    // create window and renderer
    int w = 850;
    int h = 650;
    sdl::Window win("Reactor", w, h, 0);
    win.Center();
    win.Show();
    sdl::Renderer ren(win, SDL_RENDERER_ACCELERATED);

    // create material geometry
    phys::BasicMaterial reflector1{0, 0, .1, 1, 0};
    phys::Object::Rect r1{w/2 - 40, h/2 - 40, 120, 120};
    reflector1.Init(r1, sdl::Color::white());
    phys::BasicMaterial reflector2(&reflector1);
    phys::BasicMaterial reflector3(&reflector1);
    phys::BasicMaterial reflector4(&reflector1);

    phys::Absorber absorber1{.1};
    phys::Object::Rect r2{w/2 - 130, h/2 - 40, 80, 80};
    absorber1.Init(r2, sdl::Color::blue());
    phys::Absorber absorber2(&absorber1);
    phys::Absorber absorber3(&absorber1);
    phys::Absorber absorber4(&absorber1);

    phys::BasicMaterial moderator1{0, 0, .03, .3, 0};
    phys::Object::Rect r3{w/2 + 50, h/2 - 40, 80, 80};
    moderator1.Init(r3, sdl::Color::green());
    phys::BasicMaterial moderator2(&moderator1);
    phys::BasicMaterial moderator3(&moderator1);
    phys::BasicMaterial moderator4(&moderator1);

    phys::Moderator voidmoderator1(.03, .3, 200);
    phys::Object::Rect r3b{w/2 + 130, h/2 - 40, 60, 60};
    voidmoderator1.Init(r3b, sdl::Color::lime());

    phys::Fuel fuel1(0, 0.070, 2);
    phys::Object::Rect r4{w/2 - 20, h/2 + 50, 40, 40};
    fuel1.Init(r4, sdl::Color::purple());
    phys::Fuel fuel2(&fuel1);
    phys::Fuel fuel3(&fuel1);
    phys::Fuel fuel4(&fuel1);
    phys::Fuel fuel5(&fuel1);
    phys::Fuel fuel6(&fuel1);
    phys::Fuel fuel7(&fuel1);
    phys::Fuel fuel8(&fuel1);
    phys::Fuel fuel9(&fuel1);

    phys::Object::Rect r5{w/2 + 130, h/2 + 140, 100, 100};
    phys::Detector detector1;
    detector1.Init(r5, sdl::Color::yellow(128));
    phys::Detector detector2(&detector1);

    phys::Object::Rect r6{w/2 + 80, h/2 + 80, 50, 50};
    phys::Detector detector3;
    detector3.Init(r6, sdl::Color::yellow(128));
    phys::Detector detector4(&detector3);

    phys::StreamSource stream1;
    phys::Object::Rect r7{w/2 + 130, h/2 - 40, 40, 40};
    stream1.Init(r7, sdl::Color::olive());

    // create system and a view for drawing it
    phys::System sys(w, h);
    sys.AddToolbar();
    phys::Object::Rect tb_r = sys.toolbar().rect();

    //add fuel item inside toolbar
    phys::Fuel fuel(0, 0.070, 2);
    phys::Object::Rect fr{tb_r.x+tb_r.w/2-20,tb_r.y+(int)((double)tb_r.h*.45)-20,40,40};
    fuel.Init(fr, sdl::Color::purple());
    sys.AddObject(&fuel);

    phys::BasicMaterial reflector{0, 0, .1, 1, 0};
    phys::Object::Rect rr{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.6)-40,80,80};
    reflector.Init(rr, sdl::Color::white());
    sys.AddObject(&reflector);

    phys::Absorber absorber{.1};
    phys::Object::Rect ar{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.75)-40,80,80};
    absorber.Init(ar, sdl::Color::blue());
    sys.AddObject(&absorber);

    phys::BasicMaterial moderator{0, 0, .03, .3, 0};
    phys::Object::Rect mr{tb_r.x+tb_r.w/2-40,tb_r.y+(int)((double)tb_r.h*.9)-40,80,80};
    moderator.Init(mr, sdl::Color::green());
    sys.AddObject(&moderator);

    stream1.sys(&sys);

    draw::SysView view(&sys, &ren);

    // start up the main loop
    SDL_Event ev;
    sdl::Timer timer;
    timer.Start();
    bool done = false;
    bool dragging = false;
    phys::Object* dragged = nullptr;
    phys::Object* clicked = nullptr;
    while(!done) {
      // process events
      while(SDL_PollEvent(&ev)) {
        if (ev.type == SDL_QUIT) {
          done = true;
        } else if (ev.type == SDL_MOUSEBUTTONDOWN &&
                   ev.button.button == SDL_BUTTON_RIGHT) {
          clicked = sys.ObjectFor(ev.button.x, ev.button.y);
          if (clicked->OnClick(ev.button.x, ev.button.y))
            continue;
          // create some neutrons
          phys::Neutron::Pop ns;
          for (int i = 0; i < neutron_burst; ++i) {
            double theta = uniform01(rand_gen) * 2 * 3.141592654;
            int vx = std::cos(theta) * phys::Neutron::kNomSpeed;
            int vy = std::sin(theta) * phys::Neutron::kNomSpeed;
            ns.push_back(phys::Neutron(ev.button.x, ev.button.y, vx, vy));
          }
          sys.AddNeutrons(ns);
        } else if (ev.type == SDL_MOUSEBUTTONDOWN &&
                   ev.button.button == SDL_BUTTON_LEFT) {
          dragged = sys.ObjectFor(ev.button.x, ev.button.y);
	  if(dragged->isToolbar())
	    continue;
	  if(sys.inToolbar(dragged) && !dragged->detector())
	    {
	      phys::Object* temp = dragged->clone();
	      sys.AddObject(&(*temp));
	    }
          sys.MoveTop(dragged);
          dragging = true;
        } else if (ev.type == SDL_KEYDOWN) {
          if (dragged == nullptr) {
            continue;
          }
          if (ev.key.keysym.sym == SDLK_DOWN) {
            dragged->Shift(0, 5);
          } else if (ev.key.keysym.sym == SDLK_UP) {
            dragged->Shift(0, -5);
          } else if (ev.key.keysym.sym == SDLK_LEFT) {
            dragged->Shift(-5, 0);
          } else if (ev.key.keysym.sym == SDLK_RIGHT) {
            dragged->Shift(5, 0);
          }
        } else if (ev.type == SDL_MOUSEBUTTONUP && ev.button.button == SDL_BUTTON_LEFT) {
          dragging = false;
        } else if (ev.type == SDL_MOUSEMOTION && dragging) {
          dragged->Shift(ev.motion.xrel, ev.motion.yrel);
        }
      }

      double dt = (double)timer.Mark();
      sys.Tick(dt / 1000);
      view.Render(((double)1000) / dt);
    }

    return 0;
  } catch (sdl::FatalErr err) {
    std::cout << "ERROR: " << err.what() << "\n";
    return 1;
  }
}

<|endoftext|>