Skip to content

Commit

Permalink
add screenshot
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudwu committed May 21, 2018
1 parent 0b8ea83 commit 5d456b5
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 12 deletions.
4 changes: 4 additions & 0 deletions 01-cubes.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local ant = require "ant"
local util = require "ant.util"
local common = require "ant.common"
local math3d = require "ant.math"
local bgfx = require "bgfx"

Expand All @@ -8,6 +9,8 @@ canvas = iup.canvas{
-- rastersize = "400x300",
}

canvas.keypress_cb = common.keypress_cb

dlg = iup.dialog {
canvas,
title = "01-cubes",
Expand All @@ -17,6 +20,7 @@ dlg = iup.dialog {
local ctx = {}
local time = 0
local function mainloop()
common.save_screenshot "screenshot.ppm"
math3d.reset()
bgfx.touch(0)
local mat = math3d.matrix()
Expand Down
50 changes: 50 additions & 0 deletions ant/common.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
local bgfx = require "bgfx"

local common = {}

local debug

function common:keypress_cb(key, press)
if press == 0 then
return
end
if key == iup.K_F1 then
debug = not debug
bgfx.set_debug(debug and "S" or "")
elseif key == iup.K_F12 then
bgfx.request_screenshot()
end
end

local function save_ppm(filename, data, width, height)
local f = assert(io.open(filename, "wb"))
f:write(string.format("P3\n%d %d\n255\n",width, height))
local offset = 1
local line = 0
for i = 1, width*height do
local r,g,b,a,off = string.unpack("BBBB",data,offset)
f:write(r," ",g," ",b," ")
offset = off
line = line + 1
if line > 8 then
f:write "\n"
line = 0
end
end
f:close()
end

function common.save_screenshot(filename)
local name , width, height, data = bgfx.get_screenshot()
if name then
local size = #data
if size ~= width * height * 4 then
-- not RGBA
return
end
print("Save screenshot to ", filename)
save_ppm(filename, data, width, height)
end
end

return common
141 changes: 129 additions & 12 deletions luabgfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <bgfx/c99/platform.h>

#include "luabgfx.h"
#include "simplelock.h"

#if _MSC_VER > 0
#include <malloc.h>
Expand All @@ -30,6 +31,29 @@

#endif //_MSC_VER > 0

// screenshot queue length
#define MAX_SCREENSHOT 16

struct screenshot {
uint32_t width;
uint32_t height;
uint32_t size;
void *data;
char *name;
};

struct screenshot_queue {
spinlock_t lock;
unsigned int head;
unsigned int tail;
struct screenshot *q[MAX_SCREENSHOT];
};

struct callback {
bgfx_callback_interface_t base;
struct screenshot_queue ss;
};

static void *
getfield(lua_State *L, const char *key) {
lua_getfield(L, 1, key);
Expand Down Expand Up @@ -76,11 +100,6 @@ renderer_type_id(lua_State *L, int index) {
return id;
}

struct callback {
bgfx_callback_interface_t base;
lua_State *L;
};

static void
cb_fatal(bgfx_callback_interface_t *self, bgfx_fatal_t code, const char *str) {
fprintf(stderr, "Fatal error: 0x%08x: %s", code, str);
Expand Down Expand Up @@ -124,8 +143,69 @@ static void
cb_cache_write(bgfx_callback_interface_t *self, uint64_t id, const void *data, uint32_t size) {
}

static struct screenshot *
ss_pop(struct screenshot_queue *queue) {
struct screenshot *r;
spin_lock(queue);
if (queue->head == queue->tail) {
r = NULL;
} else {
r = queue->q[queue->tail % MAX_SCREENSHOT];
++queue->tail;
}
spin_unlock(queue);
return r;
}

// succ return NULL
static struct screenshot *
ss_push(struct screenshot_queue *queue, struct screenshot *s) {
spin_lock(queue);
if ((queue->head - queue->tail) != MAX_SCREENSHOT) {
queue->q[queue->head % MAX_SCREENSHOT] = s;
++queue->head;
s = NULL;
}
spin_unlock(queue);
return s;
}

static void
ss_free(struct screenshot * s) {
if (s == NULL)
return;
free(s->name);
free(s->data);
free(s);
}

static void
cb_screen_shot(bgfx_callback_interface_t *self, const char* file, uint32_t width, uint32_t height, uint32_t pitch, const void* data, uint32_t size, bool yflip) {
struct screenshot *s = malloc(sizeof(*s));
size_t fn_sz = strlen(file);
s->name = malloc(fn_sz + 1);
memcpy(s->name, file, fn_sz+1);
s->data = malloc(size);
s->width = width;
s->height = height;
s->size = size;
uint8_t * dst = (uint8_t *)s->data;
const uint8_t * src = (const uint8_t *)data;
int line_pitch = pitch;
if (yflip) {
src += (height-1) * pitch;
line_pitch = - pitch;
}
uint32_t pixwidth = size / height;
uint32_t i;
for (i=0;i<height;i++) {
memcpy(dst, src, pixwidth);
dst += pixwidth;
src += line_pitch;
}
struct callback *cb = (struct callback *)self;
s = ss_push(&cb->ss, s);
ss_free(s);
}

static void
Expand Down Expand Up @@ -202,9 +282,9 @@ linit(lua_State *L) {
cb_capture_frame,
};
struct callback *cb = lua_newuserdata(L, sizeof(*cb));
memset(cb, 0, sizeof(*cb));
lua_setfield(L, LUA_REGISTRYINDEX, "bgfx_cb");
cb->base.vtbl = &vtbl;
cb->L = luaL_newstate();

bgfx_init_t init;

Expand Down Expand Up @@ -245,7 +325,6 @@ linit(lua_State *L) {
}

if (!bgfx_init(&init)) {
lua_close(cb->L);
return luaL_error(L, "bgfx init failed");
}
return 0;
Expand Down Expand Up @@ -653,11 +732,11 @@ static int
lshutdown(lua_State *L) {
bgfx_shutdown();
if (lua_getfield(L, LUA_REGISTRYINDEX, "bgfx_cb") == LUA_TUSERDATA) {
struct callback *cb = lua_touserdata(L, -1);
if (cb->L) {
lua_close(cb->L);
cb->L = NULL;
}
// struct callback *cb = lua_touserdata(L, -1);
// if (cb->L) {
// lua_close(cb->L);
// cb->L = NULL;
// }
}

return 0;
Expand Down Expand Up @@ -3647,6 +3726,42 @@ lsetImage(lua_State *L) {
return 0;
}

static int
lrequestScreenshot(lua_State *L) {
bgfx_frame_buffer_handle_t handle = { UINT16_MAX }; // Invalid handle (main window)
if (lua_type(L,1) == LUA_TNUMBER) {
int id = BGFX_LUAHANDLE_ID(FRAME_BUFFER, luaL_checkinteger(L, 1));
handle.idx = id;
}
const char * file = luaL_optstring(L, 2, "");
bgfx_request_screen_shot(handle, file);
return 0;
}

static int
lgetScreenshot(lua_State *L) {
int memptr = lua_toboolean(L, 1);
if (lua_getfield(L, LUA_REGISTRYINDEX, "bgfx_cb") != LUA_TUSERDATA) {
return luaL_error(L, "init first");
}
struct callback *cb = lua_touserdata(L, -1);
struct screenshot * s = ss_pop(&cb->ss);
if (s == NULL)
return 0;
lua_pushstring(L, s->name);
lua_pushinteger(L, s->width);
lua_pushinteger(L, s->height);
if (memptr) {
lua_pushlightuserdata(L, s->data);
lua_pushinteger(L, s->size);
s->data = NULL;
} else {
lua_pushlstring(L, (const char *)s->data, s->size);
}
ss_free(s);
return memptr ? 5 : 4;
}

LUAMOD_API int
luaopen_bgfx(lua_State *L) {
luaL_checkversion(L);
Expand Down Expand Up @@ -3729,6 +3844,8 @@ luaopen_bgfx(lua_State *L) {
{ "get_shader_uniforms", lgetShaderUniforms },
{ "set_view_mode", lsetViewMode },
{ "set_image", lsetImage },
{ "request_screenshot", lrequestScreenshot },
{ "get_screenshot", lgetScreenshot },
{ NULL, NULL },
};
luaL_newlib(L, l);
Expand Down
94 changes: 94 additions & 0 deletions simplelock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#ifndef SIMPLE_LOCK_H
#define SIMPLE_LOCK_H

#ifdef _MSC_VER

#include <windows.h>
#define inline __inline

#define atom_cas_long(ptr, oval, nval) (InterlockedCompareExchange((LONG volatile *)ptr, nval, oval) == oval)
#define atom_cas_pointer(ptr, oval, nval) (InterlockedCompareExchangePointer((PVOID volatile *)ptr, nval, oval) == oval)
#define atom_inc(ptr) InterlockedIncrement((LONG volatile *)ptr)
#define atom_dec(ptr) InterlockedDecrement((LONG volatile *)ptr)
#define atom_add(ptr, n) InterlockedAdd((LONG volatile *)ptr, n)
#define atom_sync() MemoryBarrier()
#define atom_spinlock(ptr) while (InterlockedExchange((LONG volatile *)ptr , 1)) {}
#define atom_spintrylock(ptr) (InterlockedExchange((LONG volatile *)ptr , 1) == 0)
#define atom_spinunlock(ptr) InterlockedExchange((LONG volatile *)ptr, 0)

#else

#define atom_cas_long(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval)
#define atom_cas_pointer(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval)
#define atom_inc(ptr) __sync_add_and_fetch(ptr, 1)
#define atom_dec(ptr) __sync_sub_and_fetch(ptr, 1)
#define atom_add(ptr, n) __sync_add_and_fetch(ptr, n)
#define atom_sync() __sync_synchronize()
#define atom_spinlock(ptr) while (__sync_lock_test_and_set(ptr,1)) {}
#define atom_spintrylock(ptr) (__sync_lock_test_and_set(ptr,1) == 0)
#define atom_spinunlock(ptr) __sync_lock_release(ptr)

#endif

typedef int spinlock_t;

/* spin lock */
#define spin_lock_init(Q) (Q)->lock = 0
#define spin_lock_destory(Q)
#define spin_lock(Q) atom_spinlock(&(Q)->lock)
#define spin_unlock(Q) atom_spinunlock(&(Q)->lock)
#define spin_trylock(Q) atom_spintrylock(&(Q)->lock)

/* read write lock */

struct rwlock {
int write;
int read;
};

static inline void
rwlock_init(struct rwlock *lock) {
lock->write = 0;
lock->read = 0;
}

static inline void
rwlock_destory(struct rwlock *lock) {
(void)lock;
// to nothing
}

static inline void
rwlock_rlock(struct rwlock *lock) {
for (;;) {
while(lock->write) {
atom_sync();
}
atom_inc(&lock->read);
if (lock->write) {
atom_dec(&lock->read);
} else {
break;
}
}
}

static inline void
rwlock_wlock(struct rwlock *lock) {
atom_spinlock(&lock->write);
while(lock->read) {
atom_sync();
}
}

static inline void
rwlock_wunlock(struct rwlock *lock) {
atom_spinunlock(&lock->write);
}

static inline void
rwlock_runlock(struct rwlock *lock) {
atom_dec(&lock->read);
}

#endif

0 comments on commit 5d456b5

Please sign in to comment.