view libclient/malikania/js-animator.cpp @ 36:9af360f34c7d

Misc: use raw duktape API
author David Demelier <markand@malikania.fr>
date Wed, 10 Aug 2016 14:30:51 +0200
parents 8e1241156034
children
line wrap: on
line source

/*
 * js-animator.cpp -- animation drawing object (JavaScript binding)
 *
 * Copyright (c) 2013-2016 Malikania Authors
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <cassert>
#include <string>

#include "js-animation.hpp"
#include "js-animator.hpp"
#include "js-point.hpp"
#include "js-window.hpp"

namespace malikania {

namespace {

const std::string Signature("\xff""\xff""malikania-animator-ptr");

Animator *self(duk_context *ctx)
{
    StackAssert sa(ctx);

    duk_push_this(ctx);
    duk_get_prop_string(ctx, -1, Signature.c_str());
    auto ptr = duk_to_pointer(ctx, -1);
    duk_pop_2(ctx);

    if (!ptr)
        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object");

    return static_cast<Animator *>(ptr);
}

duk_ret_t constructor(duk_context *ctx)
{
    if (!duk_is_constructor_call(ctx))
        duk_error(ctx, DUK_ERR_ERROR, "animator must be new-constructed");

    // Be sure animation get not collected before.
    dukx_new_animator(ctx, new Animator(*dukx_require_animation(ctx, 0)));
    duk_push_this(ctx);
    duk_dup(ctx, 0);
    duk_put_prop_string(ctx, -2, "\xff""\xff""animation-ref");

    return 0;
}

duk_ret_t destructor(duk_context *ctx)
{
    duk_get_prop_string(ctx, 0, Signature.c_str());
    delete static_cast<Animator *>(duk_to_pointer(ctx, -1));
    duk_pop(ctx);
    duk_del_prop_string(ctx, 0, Signature.c_str());

    return 0;
}

duk_ret_t draw(duk_context *ctx)
{
    try {
        self(ctx)->draw(*dukx_require_window(ctx, 0), dukx_get_point(ctx, 1));
    } catch (const std::exception &ex) {
        duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
    }

    return 0;
}

duk_ret_t update(duk_context *ctx)
{
    self(ctx)->update();

    return 0;
}

const duk_function_list_entry methods[] = {
    { "draw",   draw,       2 },
    { "update", update,     0 },
    { nullptr,  nullptr,    0 }
};

} // !namespace

void dukx_new_animator(duk_context *ctx, Animator *animator)
{
    assert(ctx);
    assert(animator);

    StackAssert sa(ctx);

    duk_push_this(ctx);
    duk_push_pointer(ctx, animator);
    duk_put_prop_string(ctx, -2, Signature.c_str());
    duk_pop(ctx);
}

Animator *dukx_require_animator(duk_context *ctx, duk_idx_t index)
{
    assert(ctx);

    StackAssert sa(ctx);

    duk_get_prop_string(ctx, index, Signature.c_str());
    auto ptr = duk_to_pointer(ctx, -1);
    duk_pop(ctx);

    if (!ptr)
        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object");

    return static_cast<Animator *>(ptr);
}

void dukx_load_animator(duk_context *ctx)
{
    assert(ctx);

    StackAssert sa(ctx);

    duk_get_global_string(ctx, "Malikania");
    duk_push_c_function(ctx, constructor, 1);
    duk_push_object(ctx);
    duk_put_function_list(ctx, -1, methods);
    duk_push_c_function(ctx, destructor, 1);
    duk_set_finalizer(ctx, -2);
    duk_put_prop_string(ctx, -2, "prototype");
    duk_put_prop_string(ctx, -2, "Animator");
    duk_pop(ctx);
}

} // !malikania