goertzenator / nifpp

C++11 Wrapper for Erlang NIF API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Various niffpp usage problems

fire opened this issue · comments

How would you write a resource constructor for https://bkaradzic.github.io/bgfx/bgfx.html#_CPPv2N4bgfx4initEN12RendererType4EnumE8uint16_t8uint16_tP9CallbackIPN2bx12ReallocatorIE

bool bgfx::init(RendererType::Enum _type, uint16_t _vendorId, uint16_t _deviceId, CallbackI *_callback, bx::ReallocatorI *_reallocator).

Where https://bkaradzic.github.io/bgfx/bgfx.html#_CPPv2N4bgfx9CallbackIE is an abstract class?

Currently it breaks on being impossible to instanstiate abstract classes.

struct CallbackI
    {
        virtual ~CallbackI() = 0;
        virtual void fatal(Fatal::Enum _code, const char* _str) = 0;
        virtual void traceVargs(const char* _filePath, uint16_t _line, const char* _format, va_list _argList) = 0;
        virtual uint32_t cacheReadSize(uint64_t _id) = 0;
        virtual bool cacheRead(uint64_t _id, void* _data, uint32_t _size) = 0;
        virtual void cacheWrite(uint64_t _id, const void* _data, uint32_t _size) = 0;
        virtual void screenShot(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t _size, bool _yflip) = 0;
        virtual void captureBegin(uint32_t _width, uint32_t _height, uint32_t _pitch, TextureFormat::Enum _format, bool _yflip) = 0;
        virtual void captureEnd() = 0;
        virtual void captureFrame(const void* _data, uint32_t _size) = 0;
    };

Here is what I have:

#ifdef __GNUC__
#define UNUSED(x) UNUSED_##x __attribute__((__unused__))
#else
#define UNUSED(x) UNUSED_##x
#endif

#include "nifpp.h"
#include <stdio.h>
#ifndef _WIN32
#include <strings.h>
#include <unistd.h>
#else
#endif

//#include "bx/platform.h"
#include "bgfx/bgfx.h"

using namespace nifpp;

extern "C" {
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
    nifpp::register_resource<bgfx::RendererType::Enum>(env, nullptr, "renderer_type");
    nifpp::register_resource<bgfx::CallbackI>(env, nullptr, "callback_interface");
    nifpp::register_resource<bx::ReallocatorI>(env, nullptr, "reallocator_interface");
    return 0;
}


static ERL_NIF_TERM _hello(ErlNifEnv *env, int UNUSED(arc),
                           const ERL_NIF_TERM UNUSED(argv[])) {
  return make(env, 0.0);
}

static ERL_NIF_TERM ex_bgfx_init(ErlNifEnv *env, int argc,
                              const ERL_NIF_TERM argv[]) {
  try {
    auto _type = nifpp::construct_resource<bgfx::RendererType::Enum>(nifpp::get<bgfx::RendererType::Enum>(env, argv[0]));
    auto _vendor_id = nifpp::get<uint16_t>(env, argv[1]);
    auto _device_id = nifpp::get<uint16_t>(env, argv[2]);
    //bgfx_callback_interface_t* _callback;
    //bgfx_reallocator_interface_t* _reallocator;
    //nifpp::get<std::string>(env, argv[3], nifpp::get<std::string>(env, argv[0]));
    //nifpp::get<std::string>(env, argv[4], _reallocator);
    auto _callback = nifpp::construct_resource<bgfx::CallbackI>(nifpp::get<bgfx::CallbackI *>(env, argv[3]));
    auto _reallocator = nifpp::construct_resource<bx::ReallocatorI>(nifpp::get<bx::ReallocatorI *>(env, argv[4]));
    return make(env, bgfx::init(*_type, _vendor_id, _device_id, &*_callback,
                                &*_reallocator));
  } catch (nifpp::badarg) {
  }
  return enif_make_badarg(env);
}

static ErlNifFunc nif_funcs[] = {
    {"_hello", 0, _hello, 0}, {"bgfx_init", 0, _hello, 0},
};

ERL_NIF_INIT(Elixir.ExBgfx.Nif, nif_funcs, NULL, NULL, NULL, NULL)
} // extern C

Two options here:

  1. It looks like you are supposed to provide your own non-abstract derivative of CallbackI that implements all the abstract methods. For example...
struct myCallback: public bgfx::CallbackI {
   ~myCallback() {...}
   ...
};

Then at that point you'll be able to ...

nifpp::register_resource<myCallback>(env, nullptr, "callback_interface");

2 . If you are already getting an abstract pointer to CallbackI from elsewhere then you should register the pointer instead of the class itself....

nifpp::register_resource<bgfx::CallbackI *>(env, nullptr, "callback_interface_ptr");

Or more probably use std::unique_ptr, std::shared_ptr, etc.

I've chosen option 2:

However, I'm having problems wrapping the enum bgfx::RendererType::Enum.

static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
    nifpp::register_resource<bgfx::RendererType::Enum>(env, nullptr, "renderer_type");
    nifpp::register_resource<bgfx::CallbackI *>(env, nullptr, "callback_interface_ptr");
    nifpp::register_resource<bx::ReallocatorI *>(env, nullptr, "reallocator_interface_ptr");
    return 0;
}
static ERL_NIF_TERM _bgfx_init(ErlNifEnv *env, int argc,
                              const ERL_NIF_TERM argv[]) {
  try {
    auto _type = nifpp::construct_resource<bgfx::RendererType::Enum>(nifpp::get<bgfx::RendererType::Enum>(env, argv[0]));
    auto _vendor_id = nifpp::get<uint16_t>(env, argv[1]);
    auto _device_id = nifpp::get<uint16_t>(env, argv[2]);
    auto _callback = nifpp::construct_resource<bgfx::CallbackI *>(nifpp::get<bgfx::CallbackI *>(env, argv[3]));
    auto _reallocator = nifpp::construct_resource<bx::ReallocatorI *>(nifpp::get<bx::ReallocatorI *>(env, argv[4]));
    return make(env, bgfx::init(*_type, _vendor_id, _device_id, *_callback,
                                *_reallocator));
  } catch (nifpp::badarg) {
  }
  return enif_make_badarg(env);
}

static ErlNifFunc nif_funcs[] = {
    {"_hello", 0, _hello, 0}, {"_bgfx_init", 0, _bgfx_init, 0},
};

From research it seems like converting the enum param to take specified atoms to be the best approach. Is it possible to do this automatically?

No, but making atom to integer lookup tables in Erlang is pretty easy.