The ragdoll API is potentially usable now, but still really limited. Enabled SQL requests by default using sqlite. Note that you'll need the sqlite dll to use this. MySQL should still be usable, but I didn't try. MySQL requires -DUSE_MYSQL to compile it, and a dll and -mysql argument to enable it. Fixed nacl. NPFTE plugin now invokes an exe to run the game rather than running the game within the browser. externvalue builtin now accepts & prefix to return a pointer instead. Fixed vector autocvars. uri_get, bufstr_add, bufstr_free, now functional. QC debugger can now show asm if line numbers are not available. Added support for QC watchpoints. Use the watchpoint command. gl_specular now give specular even without rtlights, thankfully not as blatently, but its there. android will not crash due to supported audio formats, and gles2 can be selected via a cvar (requires full FTEDroidActivity/program restart). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4152 fc73d0e0-1445-4013-8a0c-d673dee63da5
432 lines
10 KiB
C++
432 lines
10 KiB
C++
#include "../plugin.h"
|
|
#include "../engine.h"
|
|
|
|
#include "berkelium/Berkelium.hpp"
|
|
#include "berkelium/Window.hpp"
|
|
#include "berkelium/WindowDelegate.hpp"
|
|
#include "berkelium/Context.hpp"
|
|
|
|
#include <string>
|
|
|
|
qboolean inited;
|
|
|
|
class decctx
|
|
{
|
|
public:
|
|
Berkelium::Window *wnd;
|
|
int width;
|
|
int height;
|
|
unsigned int *buffer;
|
|
bool repainted;
|
|
};
|
|
|
|
class MyDelegate : public Berkelium::WindowDelegate
|
|
{
|
|
private:
|
|
decctx *ctx;
|
|
|
|
virtual void onCrashedWorker(Berkelium::Window *win)
|
|
{
|
|
int i;
|
|
Con_Printf("Berkelium worker crashed\n");
|
|
|
|
/*black it out*/
|
|
for (i = 0; i < ctx->width*ctx->height; i++)
|
|
{
|
|
ctx->buffer[i] = 0xff000000;
|
|
}
|
|
ctx->repainted = true;
|
|
}
|
|
|
|
virtual void onCrashed(Berkelium::Window *win)
|
|
{
|
|
int i;
|
|
Con_Printf("Berkelium window crashed\n");
|
|
|
|
/*black it out*/
|
|
for (i = 0; i < ctx->width*ctx->height; i++)
|
|
{
|
|
ctx->buffer[i] = 0xff000000;
|
|
}
|
|
ctx->repainted = true;
|
|
}
|
|
virtual void onUnresponsive(Berkelium::Window *win)
|
|
{
|
|
Con_Printf("Berkelium window unresponsive\n");
|
|
}
|
|
virtual void onResponsive(Berkelium::Window *win)
|
|
{
|
|
Con_Printf("Berkelium window responsive again, yay\n");
|
|
}
|
|
|
|
virtual void onPaint(Berkelium::Window *wini, const unsigned char *bitmap_in, const Berkelium::Rect &bitmap_rect, size_t num_copy_rects, const Berkelium::Rect *copy_rects, int dx, int dy, const Berkelium::Rect& scroll_rect)
|
|
{
|
|
int i;
|
|
// handle paint events...
|
|
if (dx || dy)
|
|
{
|
|
int y, m;
|
|
int dt = scroll_rect.top();
|
|
int dl = scroll_rect.left();
|
|
int w = scroll_rect.width();
|
|
int h = scroll_rect.height();
|
|
int st = dt - dy;
|
|
int sl = dl - dx;
|
|
|
|
/*bound the output rect*/
|
|
if (dt < 0)
|
|
{
|
|
st -= dt;
|
|
h += dt;
|
|
dt = 0;
|
|
}
|
|
if (dl < 0)
|
|
{
|
|
sl -= dl;
|
|
w += dl;
|
|
dl = 0;
|
|
}
|
|
/*bound the source rect*/
|
|
if (st < 0)
|
|
{
|
|
dt -= st;
|
|
h += st;
|
|
st = 0;
|
|
}
|
|
if (sl < 0)
|
|
{
|
|
dl -= sl;
|
|
w += sl;
|
|
sl = 0;
|
|
}
|
|
/*bound the width*/
|
|
m = (dl>sl)?dl:sl;
|
|
if (m + w > ctx->width)
|
|
w = ctx->width - m;
|
|
m = (dt>st)?dt:st;
|
|
if (m + h > ctx->height)
|
|
h = ctx->height - m;
|
|
|
|
if (w > 0 && h > 0)
|
|
{
|
|
if (dy > 0)
|
|
{
|
|
//if we're moving downwards, we need to write the bottom before the top (so we don't overwrite the data before its copied)
|
|
for (y = h; y >= 0; y--)
|
|
{
|
|
memmove(ctx->buffer + (dl + (dt+y)*ctx->width), ctx->buffer + (sl + (st+y)*ctx->width), w*4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//moving upwards requires we write the top row first
|
|
for (y = 0; y < h; y++)
|
|
{
|
|
memmove(ctx->buffer + (dl + (dt+y)*ctx->width), ctx->buffer + (sl + (st+y)*ctx->width), w*4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < num_copy_rects; i++)
|
|
{
|
|
unsigned int *out = ctx->buffer;
|
|
const unsigned int *in = (const unsigned int*)bitmap_in;
|
|
int x, y;
|
|
int t = copy_rects[i].top();
|
|
int l = copy_rects[i].left();
|
|
int r = copy_rects[i].width() + l;
|
|
int b = copy_rects[i].height() + t;
|
|
int w, h;
|
|
|
|
//Clip the rect to the display. This should generally happen anyway, but resizes can be lagged a bit with the whole multi-process/thread thing.
|
|
//don't need to clip to the bitmap rect, that should be correct.
|
|
if (l < 0)
|
|
l = 0;
|
|
if (t < 0)
|
|
t = 0;
|
|
if (r > ctx->width)
|
|
r = ctx->width;
|
|
if (b > ctx->height)
|
|
b = ctx->height;
|
|
w = r - l;
|
|
h = b - t;
|
|
|
|
unsigned int instride = bitmap_rect.width() - (w);
|
|
unsigned int outstride = ctx->width - (w);
|
|
|
|
out += l;
|
|
out += t * ctx->width;
|
|
|
|
in += (l-bitmap_rect.left());
|
|
in += (t-bitmap_rect.top()) * bitmap_rect.width();
|
|
|
|
for (y = 0; y < h; y++)
|
|
{
|
|
for (x = 0; x < w; x++)
|
|
{
|
|
*out++ = *in++;
|
|
}
|
|
in += instride;
|
|
out += outstride;
|
|
}
|
|
}
|
|
|
|
ctx->repainted = true;
|
|
}
|
|
|
|
public:
|
|
MyDelegate(decctx *_ctx) : ctx(_ctx) {};
|
|
};
|
|
|
|
static void *Dec_Create(char *medianame)
|
|
{
|
|
/*only respond to berkelium: media prefixes*/
|
|
if (!strncmp(medianame, "berkelium:", 10))
|
|
medianame = medianame + 10;
|
|
else if (!strcmp(medianame, "berkelium"))
|
|
medianame = (char*)"about:blank";
|
|
else if (!strncmp(medianame, "http:", 5))
|
|
medianame = medianame; //and direct http requests.
|
|
else
|
|
return NULL;
|
|
|
|
if (!inited)
|
|
{
|
|
//linux lags behind and apparently returns void, so don't bother checking return values on windows, cos I'm lazy.
|
|
Berkelium::init(Berkelium::FileString::empty());
|
|
inited = qtrue;
|
|
}
|
|
|
|
decctx *ctx = new decctx();
|
|
|
|
Berkelium::Context* context = Berkelium::Context::create();
|
|
ctx->width = 1024;
|
|
ctx->height = 1024;
|
|
ctx->repainted = false;
|
|
ctx->buffer = (unsigned int*)malloc(ctx->width * ctx->height * 4);
|
|
ctx->wnd = Berkelium::Window::create(context);
|
|
delete context;
|
|
|
|
ctx->wnd->setDelegate(new MyDelegate(ctx));
|
|
|
|
|
|
ctx->wnd->resize(ctx->width, ctx->height);
|
|
std::string url = medianame;
|
|
ctx->wnd->navigateTo(Berkelium::URLString::point_to(url.data(), url.length()));
|
|
|
|
return ctx;
|
|
}
|
|
|
|
static void *Dec_DisplayFrame(void *vctx, qboolean nosound, enum uploadfmt_e *fmt, int *width, int *height)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
*fmt = TF_BGRA32;
|
|
*width = ctx->width;
|
|
*height = ctx->height;
|
|
|
|
if (!ctx->repainted)
|
|
return NULL;
|
|
ctx->repainted = false;
|
|
return ctx->buffer;
|
|
}
|
|
static void Dec_Destroy(void *vctx)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
ctx->wnd->destroy();
|
|
delete ctx;
|
|
}
|
|
static void Dec_GetSize (void *vctx, int *width, int *height)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
*width = ctx->width;
|
|
*height = ctx->height;
|
|
}
|
|
static qboolean Dec_SetSize (void *vctx, int width, int height)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
if (ctx->width == width || ctx->height == height)
|
|
return qtrue; //no point
|
|
|
|
//there's no resize notification. apparently javascript cannot resize windows. yay.
|
|
unsigned int *newbuf = (unsigned int*)realloc(ctx->buffer, width * height * sizeof(*newbuf));
|
|
if (!newbuf)
|
|
return qfalse; //failed?!?
|
|
ctx->width = width;
|
|
ctx->height = height;
|
|
ctx->buffer = newbuf;
|
|
ctx->repainted = false;
|
|
|
|
ctx->wnd->resize(ctx->width, ctx->height);
|
|
|
|
return qtrue;
|
|
}
|
|
static void Dec_CursorMove (void *vctx, float posx, float posy)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
ctx->wnd->mouseMoved((int)(posx * ctx->width), (int)(posy * ctx->height));
|
|
}
|
|
static void Dec_Key (void *vctx, int code, int unicode, int isup)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
wchar_t wchr = unicode;
|
|
|
|
if (code >= 178 && code < 178+6)
|
|
{
|
|
code = code - 178;
|
|
//swap mouse2+3
|
|
if (code == 1)
|
|
code = 2;
|
|
else if (code == 2)
|
|
code = 1;
|
|
ctx->wnd->mouseButton(code, !isup);
|
|
}
|
|
else if (code == 188 || code == 189)
|
|
{
|
|
if (!isup)
|
|
ctx->wnd->mouseWheel(0, (code==189)?-30:30);
|
|
}
|
|
else
|
|
{
|
|
if (code)
|
|
{
|
|
int mods = 0;
|
|
if (code == 127)
|
|
code = 0x08;
|
|
else if (code == 140) //del
|
|
code = 0x2e;
|
|
else if (code == 143) //home
|
|
code = 0x24;
|
|
else if (code == 144) //end
|
|
code = 0x23;
|
|
else if (code == 141) //pgdn
|
|
code = 0x22;
|
|
else if (code == 142) //pgup
|
|
code = 0x21;
|
|
else if (code == 139) //ins
|
|
code = 0x2d;
|
|
else if (code == 132) //up
|
|
code = 0x26;
|
|
else if (code == 133) //down
|
|
code = 0x28;
|
|
else if (code == 134) //left
|
|
code = 0x25;
|
|
else if (code == 135) //right
|
|
code = 0x27;
|
|
ctx->wnd->keyEvent(!isup, mods, code, 0);
|
|
}
|
|
if (unicode && !isup)
|
|
{
|
|
wchar_t chars[2] = {unicode};
|
|
if (unicode == 127 || unicode == 8 || unicode == 9 || unicode == 27)
|
|
return;
|
|
ctx->wnd->textEvent(chars, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Dec_ChangeStream(void *vctx, char *newstream)
|
|
{
|
|
decctx *ctx = (decctx*)vctx;
|
|
|
|
if (!strncmp(newstream, "cmd:", 4))
|
|
{
|
|
if (!strcmp(newstream+4, "refresh"))
|
|
ctx->wnd->refresh();
|
|
else if (!strcmp(newstream+4, "transparent"))
|
|
ctx->wnd->setTransparent(true);
|
|
else if (!strcmp(newstream+4, "focus"))
|
|
ctx->wnd->focus();
|
|
else if (!strcmp(newstream+4, "unfocus"))
|
|
ctx->wnd->unfocus();
|
|
else if (!strcmp(newstream+4, "opaque"))
|
|
ctx->wnd->setTransparent(true);
|
|
else if (!strcmp(newstream+4, "stop"))
|
|
ctx->wnd->stop();
|
|
else if (!strcmp(newstream+4, "back"))
|
|
ctx->wnd->goBack();
|
|
else if (!strcmp(newstream+4, "forward"))
|
|
ctx->wnd->goForward();
|
|
else if (!strcmp(newstream+4, "cut"))
|
|
ctx->wnd->cut();
|
|
else if (!strcmp(newstream+4, "copy"))
|
|
ctx->wnd->copy();
|
|
else if (!strcmp(newstream+4, "paste"))
|
|
ctx->wnd->paste();
|
|
else if (!strcmp(newstream+4, "del"))
|
|
ctx->wnd->del();
|
|
else if (!strcmp(newstream+4, "selectall"))
|
|
ctx->wnd->selectAll();
|
|
}
|
|
else if (!strncmp(newstream, "javascript:", 11))
|
|
{
|
|
newstream+=11;
|
|
int len = mblen(newstream, MB_CUR_MAX);
|
|
wchar_t *wchrs = (wchar_t *)malloc((len+1)*2);
|
|
len = mbstowcs(wchrs, newstream, len);
|
|
ctx->wnd->executeJavascript(Berkelium::WideString::point_to(wchrs, len));
|
|
free(wchrs);
|
|
}
|
|
else
|
|
{
|
|
std::string url = newstream;
|
|
ctx->wnd->navigateTo(Berkelium::URLString::point_to(url.data(), url.length()));
|
|
}
|
|
}
|
|
|
|
static bool Dec_Init(void)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static qintptr_t Dec_Tick(qintptr_t *args)
|
|
{
|
|
//need to keep it ticking over, if any work is to be done.
|
|
if (inited)
|
|
Berkelium::update();
|
|
return 0;
|
|
}
|
|
|
|
static qintptr_t Dec_Shutdown(qintptr_t *args)
|
|
{
|
|
//force-kill all.
|
|
if (inited)
|
|
Berkelium::destroy();
|
|
inited = qfalse;
|
|
return 0;
|
|
}
|
|
|
|
static media_decoder_funcs_t decoderfuncs =
|
|
{
|
|
Dec_Create,
|
|
Dec_DisplayFrame,
|
|
NULL,//doneframe
|
|
Dec_Destroy,
|
|
NULL,//rewind
|
|
|
|
Dec_CursorMove,
|
|
Dec_Key,
|
|
Dec_SetSize,
|
|
Dec_GetSize,
|
|
Dec_ChangeStream
|
|
};
|
|
|
|
extern "C" qintptr_t Plug_Init(qintptr_t *args)
|
|
{
|
|
if (!Plug_Export("Tick", Dec_Tick))
|
|
{
|
|
Con_Printf("Berkelium plugin failed: Engine doesn't support Tick feature\n");
|
|
return false;
|
|
}
|
|
if (!Plug_Export("Shutdown", Dec_Shutdown))
|
|
{
|
|
Con_Printf("Berkelium plugin warning: Engine doesn't support Shutdown feature\n");
|
|
// return false;
|
|
}
|
|
if (!Plug_ExportNative("Media_VideoDecoder", &decoderfuncs))
|
|
{
|
|
Con_Printf("Berkelium plugin failed: Engine doesn't support media decoder plugins\n");
|
|
return false;
|
|
}
|
|
return Dec_Init();
|
|
}
|
|
|