Files
Michael Fabian 'Xaymar' Dirks 09be5488e1 runtime/lib: C++ify
2019-01-18 21:26:57 +01:00

1640 lines
37 KiB
C++

#include "bbgraphics.hpp"
#include "bbinput.hpp"
#include <fstream>
#include <gxmovie.hpp>
gxGraphics* gx_graphics;
gxCanvas* gx_canvas;
struct GfxMode {
int w, h, d, caps;
};
class bbImage {
public:
bbImage(const std::vector<gxCanvas*>& f) : frames(f) {}
~bbImage()
{
for (int k = 0; k < frames.size(); ++k) {
gx_graphics->freeCanvas(frames[k]);
}
}
const std::vector<gxCanvas*>& getFrames() const
{
return frames;
}
void replaceFrame(int n, gxCanvas* c)
{
gx_graphics->freeCanvas(frames[n]);
frames[n] = c;
}
private:
std::vector<gxCanvas*> frames;
};
//degrees to radians
static const float s_degreesToRadians = 0.0174532925199432957692369076848861f;
static int gx_driver; //current graphics driver
static bool filter;
static bool auto_dirty;
static bool auto_midhandle;
static std::set<bbImage*> image_set;
static int curs_x, curs_y;
static gxCanvas* p_canvas;
static gxFont* curr_font;
static unsigned curr_color;
static unsigned curr_clsColor;
static std::vector<GfxMode> gfx_modes;
#ifdef _DEBUG
static inline void debugImage(bbImage* i, int frame = 0)
{
if (debug) {
if (!image_set.count(i))
ThrowRuntimeException("Image does not exist");
if (frame >= i->getFrames().size())
ThrowRuntimeException("Image frame out of range");
}
}
static inline void debugFont(gxFont* f)
{
if (debug) {
if (!gx_graphics->verifyFont(f))
ThrowRuntimeException("Font does not exist");
}
}
static inline void debugCanvas(gxCanvas* c)
{
if (debug) {
if (!gx_graphics->verifyCanvas(c))
ThrowRuntimeException("Buffer does not exist");
}
}
static inline void debugDriver(int n)
{
if (debug) {
if (n < 1 || n > gx_runtime->enumerateGraphicsDrivers()) {
ThrowRuntimeException("Illegal graphics driver index");
}
}
}
static inline void debugMode(int n)
{
if (debug) {
if (n < 1 || n > gfx_modes.size()) {
ThrowRuntimeException("Illegal graphics mode index");
}
}
}
#else
#define debugImage
#define debugFont
#define debugCanvas
#define debugDriver
#define debugMode
#endif
void bbFreeImage(bbImage* i);
static void freeGraphics()
{
extern void blitz3d_close();
blitz3d_close();
while (image_set.size())
bbFreeImage(*image_set.begin());
if (p_canvas) {
gx_graphics->freeCanvas(p_canvas);
p_canvas = 0;
}
}
#define RED(_X_) (((_X_) >> 16) & 0xff)
#define GRN(_X_) (((_X_) >> 8) & 0xff)
#define BLU(_X_) ((_X_)&0xff)
static int getPixel(gxCanvas* c, float x, float y)
{
debugCanvas(c);
x -= .5f;
y -= .5f;
float fx = floor(x), fy = floor(y);
int ix = fx, iy = fy;
fx = x - fx;
fy = y - fy;
int tl = c->getPixel(ix, iy);
int tr = c->getPixel(ix + 1, iy);
int br = c->getPixel(ix + 1, iy + 1);
int bl = c->getPixel(ix, iy + 1);
float w1 = (1 - fx) * (1 - fy), w2 = fx * (1 - fy), w3 = (1 - fx) * fy, w4 = fx * fy;
float r = RED(tl) * w1 + RED(tr) * w2 + RED(bl) * w3 + RED(br) * w4;
float g = GRN(tl) * w1 + GRN(tr) * w2 + GRN(bl) * w3 + GRN(br) * w4;
float b = BLU(tl) * w1 + BLU(tr) * w2 + BLU(bl) * w3 + BLU(br) * w4;
return (int(r + .5f) << 16) | (int(g + .5f) << 8) | int(b + .5f);
}
struct vec2 {
float x, y;
};
static vec2 vrot(float m[2][2], const vec2& v)
{
vec2 t;
t.x = m[0][0] * v.x + m[0][1] * v.y;
t.y = m[1][0] * v.x + m[1][1] * v.y;
return t;
}
static float vmin(float a, float b, float c, float d)
{
float t = a;
if (b < t)
t = b;
if (c < t)
t = c;
if (d < t)
t = d;
return t;
}
static float vmax(float a, float b, float c, float d)
{
float t = a;
if (b > t)
t = b;
if (c > t)
t = c;
if (d > t)
t = d;
return t;
}
static gxCanvas* tformCanvas(gxCanvas* c, float m[2][2], int x_handle, int y_handle)
{
vec2 v, v0, v1, v2, v3;
float i[2][2];
float dt = 1.0f / (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
i[0][0] = dt * m[1][1];
i[1][0] = -dt * m[1][0];
i[0][1] = -dt * m[0][1];
i[1][1] = dt * m[0][0];
float ox = x_handle, oy = y_handle;
v0.x = -ox;
v0.y = -oy; //tl
v1.x = c->getWidth() - ox;
v1.y = -oy; //tr
v2.x = c->getWidth() - ox;
v2.y = c->getHeight() - oy; //br
v3.x = -ox;
v3.y = c->getHeight() - oy; //bl
v0 = vrot(m, v0);
v1 = vrot(m, v1);
v2 = vrot(m, v2);
v3 = vrot(m, v3);
float minx = floor(vmin(v0.x, v1.x, v2.x, v3.x));
float miny = floor(vmin(v0.y, v1.y, v2.y, v3.y));
float maxx = ceil(vmax(v0.x, v1.x, v2.x, v3.x));
float maxy = ceil(vmax(v0.y, v1.y, v2.y, v3.y));
int iw = maxx - minx, ih = maxy - miny;
gxCanvas* t = gx_graphics->createCanvas(iw, ih, 0);
t->setHandle(-minx, -miny);
t->setMask(c->getMask());
c->lock();
t->lock();
v.y = miny + .5f;
for (int y = 0; y < ih; ++v.y, ++y) {
v.x = minx + .5f;
for (int x = 0; x < iw; ++v.x, ++x) {
vec2 q = vrot(i, v);
unsigned rgb = filter ? getPixel(c, q.x + ox, q.y + oy) : c->getPixel(floor(q.x + ox), floor(q.y + oy));
t->setPixel(x, y, rgb);
}
}
t->unlock();
c->unlock();
return t;
}
static bool saveCanvas(gxCanvas* c, const std::string& f)
{
std::ofstream out(f.c_str(), std::ios::binary);
if (!out.good())
return false;
int tempsize = (c->getWidth() * 3 + 3) & ~3;
BITMAPFILEHEADER bf;
memset(&bf, 0, sizeof(bf));
bf.bfType = 'MB';
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + tempsize * c->getHeight();
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bi;
memset(&bi, 0, sizeof(bi));
bi.biSize = sizeof(bi);
bi.biWidth = c->getWidth();
bi.biHeight = c->getHeight();
bi.biPlanes = 1;
bi.biBitCount = 24;
out.write((char*)&bf, sizeof(bf));
out.write((char*)&bi, sizeof(bi));
unsigned char* temp = new unsigned char[tempsize];
memset(temp, 0, tempsize);
c->lock();
for (int y = c->getHeight() - 1; y >= 0; --y) {
unsigned char* dest = temp;
for (int x = 0; x < c->getWidth(); ++x) {
unsigned rgb = c->getPixelFast(x, y);
*dest++ = rgb & 0xff;
*dest++ = (rgb >> 8) & 0xff;
*dest++ = (rgb >> 16) & 0xff;
}
out.write((char*)temp, tempsize);
}
c->unlock();
delete[] temp;
return out.good();
}
int bbCountGfxDrivers()
{
return gx_runtime->enumerateGraphicsDrivers();
}
BBStr* bbGfxDriverName(int n)
{
debugDriver(n);
std::string t;
int caps;
gx_runtime->graphicsDriverInfo(n - 1, &t, &caps);
return new BBStr(t);
}
void bbSetGfxDriver(int n)
{
debugDriver(n);
gfx_modes.clear();
gx_driver = n - 1;
}
int bbCountGfxModes()
{
gfx_modes.clear();
int n = gx_runtime->countGraphicsModes(gx_driver);
for (int k = 0; k < n; ++k) {
GfxMode m;
gx_runtime->graphicsModeInfo(gx_driver, k, &m.w, &m.h, &m.d, &m.caps);
gfx_modes.push_back(m);
}
return gfx_modes.size();
}
int bbGfxModeWidth(int n)
{
debugMode(n);
return gfx_modes[n - 1].w;
}
int bbGfxModeHeight(int n)
{
debugMode(n);
return gfx_modes[n - 1].h;
}
int bbGfxModeDepth(int n)
{
debugMode(n);
return gfx_modes[n - 1].d;
}
static int modeExists(int w, int h, int d, bool bb3d)
{
int cnt = gx_runtime->countGraphicsModes(gx_driver);
for (int k = 0; k < cnt; ++k) {
int tw, th, td, tc;
gx_runtime->graphicsModeInfo(gx_driver, k, &tw, &th, &td, &tc);
if (bb3d && !(tc & gxRuntime::GFXMODECAPS_3D))
continue;
if (w == tw && h == th && d == td)
return 1;
}
return 0;
}
int bbGfxModeExists(int w, int h, int d)
{
return modeExists(w, h, d, false);
}
int bbGfxDriver3D(int n)
{
debugDriver(n);
std::string t;
int caps;
gx_runtime->graphicsDriverInfo(n - 1, &t, &caps);
return (caps & gxRuntime::GFXMODECAPS_3D) ? 1 : 0;
}
int bbCountGfxModes3D()
{
gfx_modes.clear();
int n = gx_runtime->countGraphicsModes(gx_driver);
for (int k = 0; k < n; ++k) {
GfxMode m;
gx_runtime->graphicsModeInfo(gx_driver, k, &m.w, &m.h, &m.d, &m.caps);
if (m.caps & gxRuntime::GFXMODECAPS_3D)
gfx_modes.push_back(m);
}
return gfx_modes.size();
}
int bbGfxMode3DExists(int w, int h, int d)
{
return modeExists(w, h, d, true);
}
int bbGfxMode3D(int n)
{
debugMode(n);
return gfx_modes[n - 1].caps & gxRuntime::GFXMODECAPS_3D ? 1 : 0;
}
int bbWindowed3D()
{
int tc;
gx_runtime->windowedModeInfo(&tc);
return (tc & gxRuntime::GFXMODECAPS_3D) ? 1 : 0;
}
int bbTotalVidMem()
{
return gx_graphics->getTotalVidmem();
}
int bbAvailVidMem()
{
return gx_graphics->getAvailVidmem();
}
void bbSetBuffer(gxCanvas* buff)
{
debugCanvas(buff);
gx_canvas = buff;
curs_x = curs_y = 0;
gx_canvas->setOrigin(0, 0);
gx_canvas->setViewport(0, 0, gx_canvas->getWidth(), gx_canvas->getHeight());
gx_canvas->setColor(curr_color);
gx_canvas->setClsColor(curr_clsColor);
gx_canvas->setFont(curr_font);
// Switch Render Target
//if (gx_graphics != nullptr) {
// if (gx_graphics->dir3dDev != nullptr) {
// LPDIRECTDRAWSURFACE7 pddsOldRenderTarget = NULL, pddsNewRenderTarget = gx_canvas->getSurface();
// gx_graphics->dir3dDev->GetRenderTarget(&pddsOldRenderTarget);
// if (pddsOldRenderTarget) {
// LPDIRECTDRAWSURFACE7 pddsZBuffer = NULL;
// DDSCAPS2 ddscaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
// pddsOldRenderTarget->GetAttachedSurface(&ddscaps, &pddsZBuffer);
// if (pddsZBuffer) {
// pddsOldRenderTarget->DeleteAttachedSurface(0, pddsZBuffer);
// pddsNewRenderTarget->AddAttachedSurface(pddsZBuffer);
// //pddsZBuffer->Release();
// }
// //pddsOldRenderTarget->Release();
// }
// gx_graphics->dir3dDev->SetRenderTarget(pddsNewRenderTarget, 0);
// }
//}
}
gxCanvas* bbGraphicsBuffer()
{
return gx_canvas;
}
int bbLoadBuffer(gxCanvas* c, BBStr* str)
{
debugCanvas(c);
std::string s = *str;
delete str;
gxCanvas* t = gx_graphics->loadCanvas(s, 0);
if (!t)
return 0;
float m[2][2];
m[0][0] = (float)c->getWidth() / (float)t->getWidth();
m[1][1] = (float)c->getHeight() / (float)t->getHeight();
m[1][0] = m[0][1] = 0;
gxCanvas* p = tformCanvas(t, m, 0, 0);
gx_graphics->freeCanvas(t);
int ox, oy;
c->getOrigin(&ox, &oy);
c->setOrigin(0, 0);
c->blit(0, 0, p, 0, 0, p->getWidth(), p->getHeight(), true);
gx_graphics->freeCanvas(p);
return 1;
}
int bbSaveBuffer(gxCanvas* c, BBStr* str)
{
debugCanvas(c);
std::string t = *str;
delete str;
return saveCanvas(c, t) ? 1 : 0;
}
void bbBufferDirty(gxCanvas* c)
{
debugCanvas(c);
c->backup();
}
static void graphics(int w, int h, int d, int flags)
{
freeGraphics();
gx_runtime->closeGraphics(gx_graphics);
gx_graphics = gx_runtime->openGraphics(w, h, d, gx_driver, flags);
if (!gx_runtime->idle())
ThrowRuntimeException(0);
if (!gx_graphics) {
ThrowRuntimeException("Unable to set graphics mode");
}
curr_clsColor = 0;
curr_color = 0xffffffff;
curr_font = gx_graphics->getDefaultFont();
gxCanvas* buff = (flags & gxGraphics::GRAPHICS_3D) ? gx_graphics->getBackCanvas() : gx_graphics->getFrontCanvas();
bbSetBuffer(buff);
}
void bbGraphics(int w, int h, int d, int mode)
{
int flags = 0;
switch (mode) {
case 0:
flags |= debug ? gxGraphics::GRAPHICS_WINDOWED : 0;
break;
case 1:
break;
case 2:
flags |= gxGraphics::GRAPHICS_WINDOWED;
break;
case 3:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_SCALED;
break;
case 6:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_AUTOSUSPEND;
break;
case 7:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_SCALED | gxGraphics::GRAPHICS_AUTOSUSPEND;
break;
default:
ThrowRuntimeException("Illegal Graphics mode");
}
graphics(w, h, d, flags);
}
void bbGraphics3D(int w, int h, int d, int mode)
{
int flags = gxGraphics::GRAPHICS_3D;
switch (mode) {
case 0:
flags |= (debug && bbWindowed3D()) ? gxGraphics::GRAPHICS_WINDOWED : 0;
break;
case 1:
break;
case 2:
flags |= gxGraphics::GRAPHICS_WINDOWED;
break;
case 3:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_SCALED;
break;
case 6:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_AUTOSUSPEND;
break;
case 7:
flags |= gxGraphics::GRAPHICS_WINDOWED | gxGraphics::GRAPHICS_SCALED | gxGraphics::GRAPHICS_AUTOSUSPEND;
break;
default:
ThrowRuntimeException("Illegal Graphics3D mode");
}
graphics(w, h, d, flags);
extern void blitz3d_open();
blitz3d_open();
}
void bbEndGraphics()
{
freeGraphics();
gx_runtime->closeGraphics(gx_graphics);
gx_graphics = gx_runtime->openGraphics(400, 300, 0, 0, gxGraphics::GRAPHICS_WINDOWED);
if (!gx_runtime->idle())
ThrowRuntimeException(0);
if (gx_graphics) {
curr_clsColor = 0;
curr_color = 0xffffffff;
curr_font = gx_graphics->getDefaultFont();
bbSetBuffer(gx_graphics->getFrontCanvas());
return;
}
ThrowRuntimeException("Unable to set graphics mode");
}
int bbGraphicsLost()
{
return gx_runtime->graphicsLost();
}
void bbSetGamma(int r, int g, int b, float dr, float dg, float db)
{
if (dr < 0)
dr = 0;
else if (dr > 255.0f)
dr = 255.0f;
if (dg < 0)
dg = 0;
else if (dg > 255.0f)
dg = 255.0f;
if (db < 0)
db = 0;
else if (db > 255.0f)
db = 255.0f;
gx_graphics->setGamma(r, g, b, dr, dg, db);
}
void bbUpdateGamma(int calibrate)
{
gx_graphics->updateGamma(!!calibrate);
}
float bbGammaRed(int n)
{
float dr, dg, db;
gx_graphics->getGamma(n, n, n, &dr, &dg, &db);
return dr;
}
float bbGammaGreen(int n)
{
float dr, dg, db;
gx_graphics->getGamma(n, n, n, &dr, &dg, &db);
return dg;
}
float bbGammaBlue(int n)
{
float dr, dg, db;
gx_graphics->getGamma(n, n, n, &dr, &dg, &db);
return db;
}
gxCanvas* bbFrontBuffer()
{
return gx_graphics->getFrontCanvas();
}
gxCanvas* bbBackBuffer()
{
return gx_graphics->getBackCanvas();
}
void bbLockBuffer(gxCanvas* buff)
{
if (buff)
debugCanvas(buff);
(buff ? buff : gx_canvas)->lock();
}
void bbUnlockBuffer(gxCanvas* buff)
{
if (buff)
debugCanvas(buff);
(buff ? buff : gx_canvas)->unlock();
}
int bbReadPixel(int x, int y, gxCanvas* buff)
{
if (buff)
debugCanvas(buff);
return (buff ? buff : gx_canvas)->getPixel(x, y);
}
void bbWritePixel(int x, int y, int argb, gxCanvas* buff)
{
if (buff)
debugCanvas(buff);
(buff ? buff : gx_canvas)->setPixel(x, y, argb);
}
int bbReadPixelFast(int x, int y, gxCanvas* buff)
{
return (buff ? buff : gx_canvas)->getPixelFast(x, y);
}
void bbWritePixelFast(int x, int y, int argb, gxCanvas* buff)
{
(buff ? buff : gx_canvas)->setPixelFast(x, y, argb);
}
void bbCopyPixel(int src_x, int src_y, gxCanvas* src, int dest_x, int dest_y, gxCanvas* buff)
{
(buff ? buff : gx_canvas)->copyPixel(dest_x, dest_y, src ? src : gx_canvas, src_x, src_y);
}
void bbCopyPixelFast(int src_x, int src_y, gxCanvas* src, int dest_x, int dest_y, gxCanvas* buff)
{
(buff ? buff : gx_canvas)->copyPixelFast(dest_x, dest_y, src ? src : gx_canvas, src_x, src_y);
}
int bbScanLine()
{
return gx_graphics->getScanLine();
}
void bbVWait(int n)
{
gx_graphics->vwait();
if (!gx_runtime->idle())
ThrowRuntimeException(0);
}
void bbFlip(int vwait)
{
gx_graphics->flip(vwait ? true : false);
if (!gx_runtime->idle())
ThrowRuntimeException(0);
}
int bbGraphicsWidth()
{
return gx_graphics->getWidth();
}
int bbGraphicsHeight()
{
return gx_graphics->getHeight();
}
int bbGraphicsDepth()
{
return gx_graphics->getDepth();
}
void bbOrigin(int x, int y)
{
gx_canvas->setOrigin(x, y);
}
void bbViewport(int x, int y, int w, int h)
{
gx_canvas->setViewport(x, y, w, h);
}
void bbColor(int r, int g, int b)
{
gx_canvas->setColor(curr_color = (r << 16) | (g << 8) | b);
}
void bbGetColor(int x, int y)
{
gx_canvas->setColor(curr_color = gx_canvas->getPixel(x, y));
}
int bbColorRed()
{
return (gx_canvas->getColor() >> 16) & 0xff;
}
int bbColorGreen()
{
return (gx_canvas->getColor() >> 8) & 0xff;
}
int bbColorBlue()
{
return gx_canvas->getColor() & 0xff;
}
void bbClsColor(int r, int g, int b)
{
gx_canvas->setClsColor(curr_clsColor = (r << 16) | (g << 8) | b);
}
void bbSetFont(gxFont* f)
{
debugFont(f);
gx_canvas->setFont(curr_font = f);
}
void bbCls()
{
gx_canvas->cls();
}
void bbPlot(int x, int y)
{
gx_canvas->plot(x, y);
}
void bbLine(int x1, int y1, int x2, int y2)
{
gx_canvas->line(x1, y1, x2, y2);
}
void bbRect(int x, int y, int w, int h, int solid)
{
gx_canvas->rect(x, y, w, h, solid ? true : false);
}
void bbOval(int x, int y, int w, int h, int solid)
{
gx_canvas->oval(x, y, w, h, solid ? true : false);
}
void bbText(int x, int y, BBStr* str, int centre_x, int centre_y)
{
if (centre_x)
x -= curr_font->getWidth(*str) / 2;
if (centre_y)
y -= curr_font->getHeight() / 2;
gx_canvas->text(x, y, *str);
delete str;
}
void bbCopyRect(int sx, int sy, int w, int h, int dx, int dy, gxCanvas* src, gxCanvas* dest)
{
if (src)
debugCanvas(src);
else
src = gx_canvas;
if (dest)
debugCanvas(dest);
else
dest = gx_canvas;
dest->blit(dx, dy, src, sx, sy, w, h, true);
}
gxFont* bbLoadFont(BBStr* name, int height, int bold, int italic, int underline)
{
int flags =
(bold ? gxFont::FONT_BOLD : 0) | (italic ? gxFont::FONT_ITALIC : 0) | (underline ? gxFont::FONT_UNDERLINE : 0);
gxFont* font = gx_graphics->loadFont(*name, height, flags);
delete name;
return font;
}
void bbFreeFont(gxFont* f)
{
debugFont(f);
if (f == curr_font)
bbSetFont(gx_graphics->getDefaultFont());
gx_graphics->freeFont(f);
}
int bbFontWidth()
{
return curr_font->getWidth();
}
int bbFontHeight()
{
return curr_font->getHeight();
}
int bbStringWidth(BBStr* str)
{
std::string t = *str;
delete str;
return curr_font->getWidth(t);
}
int bbStringHeight(BBStr* str)
{
delete str;
return curr_font->getHeight();
}
gxMovie* bbOpenMovie(BBStr* s)
{
gxMovie* movie = gx_graphics->openMovie(*s, 0);
delete s;
return movie;
}
int bbDrawMovie(gxMovie* movie, int x, int y, int w, int h)
{
if (w < 0)
w = movie->getWidth();
if (h < 0)
h = movie->getHeight();
int playing = movie->draw(gx_canvas, x, y, w, h);
if (!gx_runtime->idle())
ThrowRuntimeException(0);
return playing;
}
int bbMovieWidth(gxMovie* movie)
{
return movie->getWidth();
}
int bbMovieHeight(gxMovie* movie)
{
return movie->getHeight();
}
int bbMoviePlaying(gxMovie* movie)
{
return movie->isPlaying();
}
void bbCloseMovie(gxMovie* movie)
{
gx_graphics->closeMovie(movie);
}
bbImage* bbLoadImage(BBStr* s)
{
std::string t = *s;
delete s;
gxCanvas* c = gx_graphics->loadCanvas(t, 0);
if (!c)
return 0;
if (auto_dirty)
c->backup();
if (auto_midhandle)
c->setHandle(c->getWidth() / 2, c->getHeight() / 2);
std::vector<gxCanvas*> frames;
frames.push_back(c);
bbImage* i = new bbImage(frames);
image_set.insert(i);
return i;
}
bbImage* bbLoadAnimImage(BBStr* s, int w, int h, int first, int cnt)
{
std::string t = *s;
delete s;
if (cnt < 1)
ThrowRuntimeException("Illegal frame count");
if (first < 0)
ThrowRuntimeException("Illegal first frame");
gxCanvas* pic = gx_graphics->loadCanvas(t, gxCanvas::CANVAS_NONDISPLAY);
if (!pic)
return 0;
//frames per row, per picture
int fpr = pic->getWidth() / w;
int fpp = pic->getHeight() / h * fpr;
if (first + cnt > fpp) {
gx_graphics->freeCanvas(pic);
ThrowRuntimeException("Not enough frames in bitmap");
}
//x,y of first frame...
std::vector<gxCanvas*> frames;
int src_x = first % fpr * w, src_y = first / fpr * h;
for (int k = 0; k < cnt; ++k) {
gxCanvas* c = gx_graphics->createCanvas(w, h, 0);
if (!c) {
for (--k; k >= 0; --k)
gx_graphics->freeCanvas(frames[k]);
gx_graphics->freeCanvas(pic);
return 0;
}
c->blit(0, 0, pic, src_x, src_y, w, h, true);
if (auto_dirty)
c->backup();
if (auto_midhandle)
c->setHandle(c->getWidth() / 2, c->getHeight() / 2);
frames.push_back(c);
src_x += w;
if (src_x + w > pic->getWidth()) {
src_x = 0;
src_y += h;
}
}
gx_graphics->freeCanvas(pic);
bbImage* i = new bbImage(frames);
image_set.insert(i);
return i;
}
bbImage* bbCopyImage(bbImage* i)
{
debugImage(i);
std::vector<gxCanvas*> frames;
const std::vector<gxCanvas*>& f = i->getFrames();
for (int k = 0; k < f.size(); ++k) {
gxCanvas* t = f[k];
gxCanvas* c = gx_graphics->createCanvas(t->getWidth(), t->getHeight(), 0);
if (!c) {
for (--k; k >= 0; --k)
gx_graphics->freeCanvas(frames[k]);
return 0;
}
int x, y;
t->getHandle(&x, &y);
t->setHandle(0, 0);
c->blit(0, 0, t, 0, 0, t->getWidth(), t->getHeight(), true);
if (auto_dirty)
c->backup();
t->setHandle(x, y);
c->setHandle(x, y);
c->setMask(t->getMask());
frames.push_back(c);
}
bbImage* t = new bbImage(frames);
image_set.insert(t);
return t;
}
bbImage* bbCreateImage(int w, int h, int n)
{
std::vector<gxCanvas*> frames;
for (int k = 0; k < n; ++k) {
gxCanvas* c = gx_graphics->createCanvas(w, h, 0);
if (!c) {
for (--k; k >= 0; --k)
gx_graphics->freeCanvas(frames[k]);
return 0;
}
if (auto_dirty)
c->backup();
if (auto_midhandle)
c->setHandle(c->getWidth() / 2, c->getHeight() / 2);
frames.push_back(c);
}
bbImage* i = new bbImage(frames);
image_set.insert(i);
return i;
}
void bbFreeImage(bbImage* i)
{
if (!image_set.erase(i))
return;
const std::vector<gxCanvas*>& f = i->getFrames();
for (int k = 0; k < f.size(); ++k) {
if (f[k] == gx_canvas) {
bbSetBuffer(gx_graphics->getFrontCanvas());
break;
}
}
delete i;
}
int bbSaveImage(bbImage* i, BBStr* str, int n)
{
debugImage(i, n);
std::string t = *str;
delete str;
gxCanvas* c = i->getFrames()[n];
return saveCanvas(c, t) ? 1 : 0;
}
void bbGrabImage(bbImage* i, int x, int y, int n)
{
debugImage(i, n);
gxCanvas* c = i->getFrames()[n];
int src_ox, src_oy, dst_hx, dst_hy;
gx_canvas->getOrigin(&src_ox, &src_oy);
c->getHandle(&dst_hx, &dst_hy);
x += src_ox - dst_hx;
y += src_oy - dst_hy;
c->setViewport(0, 0, c->getWidth(), c->getHeight());
c->blit(0, 0, gx_canvas, x, y, c->getWidth(), c->getHeight(), true);
if (auto_dirty)
c->backup();
}
gxCanvas* bbImageBuffer(bbImage* i, int n)
{
debugImage(i, n);
return i->getFrames()[n];
}
void bbDrawImage(bbImage* i, int x, int y, int frame)
{
debugImage(i, frame);
gxCanvas* c = i->getFrames()[frame];
gx_canvas->blit(x, y, c, 0, 0, c->getWidth(), c->getHeight(), false);
}
void bbDrawBlock(bbImage* i, int x, int y, int frame)
{
debugImage(i, frame);
gxCanvas* c = i->getFrames()[frame];
gx_canvas->blit(x, y, c, 0, 0, c->getWidth(), c->getHeight(), true);
}
static void tile(bbImage* i, int x, int y, int frame, bool solid)
{
gxCanvas* c = i->getFrames()[frame];
int hx, hy;
c->getHandle(&hx, &hy);
int w = c->getWidth(), h = c->getHeight();
int ox, oy, vp_x, vp_y, vp_w, vp_h;
gx_canvas->getOrigin(&ox, &oy);
gx_canvas->getViewport(&vp_x, &vp_y, &vp_w, &vp_h);
int dx = vp_x - ox + hx;
int dy = vp_y - oy + hy;
x -= dx;
y -= dy;
dx += (x >= 0 ? x % w : w - (-x % w));
dy += (y >= 0 ? y % h : h - (-y % h));
for (y = -h; y < vp_h; y += h) {
for (x = -w; x < vp_w; x += w) {
gx_canvas->blit(x + dx, y + dy, c, 0, 0, w, h, solid);
}
}
}
void bbTileImage(bbImage* i, int x, int y, int frame)
{
debugImage(i, frame);
tile(i, x, y, frame, false);
}
void bbTileBlock(bbImage* i, int x, int y, int frame)
{
debugImage(i, frame);
tile(i, x, y, frame, true);
}
void bbDrawImageRect(bbImage* i, int x, int y, int r_x, int r_y, int r_w, int r_h, int frame)
{
debugImage(i, frame);
gxCanvas* c = i->getFrames()[frame];
gx_canvas->blit(x, y, c, r_x, r_y, r_w, r_h, false);
}
void bbDrawBlockRect(bbImage* i, int x, int y, int r_x, int r_y, int r_w, int r_h, int frame)
{
debugImage(i, frame);
gxCanvas* c = i->getFrames()[frame];
gx_canvas->blit(x, y, c, r_x, r_y, r_w, r_h, true);
}
void bbMaskImage(bbImage* i, int r, int g, int b)
{
debugImage(i);
unsigned argb = (r << 16) | (g << 8) | b;
const std::vector<gxCanvas*>& f = i->getFrames();
for (int k = 0; k < f.size(); ++k)
f[k]->setMask(argb);
}
void bbHandleImage(bbImage* i, int x, int y)
{
debugImage(i);
const std::vector<gxCanvas*>& f = i->getFrames();
for (int k = 0; k < f.size(); ++k)
f[k]->setHandle(x, y);
}
void bbMidHandle(bbImage* i)
{
debugImage(i);
const std::vector<gxCanvas*>& f = i->getFrames();
for (int k = 0; k < f.size(); ++k)
f[k]->setHandle(f[k]->getWidth() / 2, f[k]->getHeight() / 2);
}
void bbAutoMidHandle(int enable)
{
auto_midhandle = enable ? true : false;
}
int bbImageWidth(bbImage* i)
{
debugImage(i);
return i->getFrames()[0]->getWidth();
}
int bbImageHeight(bbImage* i)
{
debugImage(i);
return i->getFrames()[0]->getHeight();
}
int bbImageXHandle(bbImage* i)
{
debugImage(i);
int x, y;
i->getFrames()[0]->getHandle(&x, &y);
return x;
}
int bbImageYHandle(bbImage* i)
{
debugImage(i);
int x, y;
i->getFrames()[0]->getHandle(&x, &y);
return y;
}
int bbImagesOverlap(bbImage* i1, int x1, int y1, bbImage* i2, int x2, int y2)
{
debugImage(i1);
debugImage(i2);
gxCanvas* c1 = i1->getFrames()[0];
gxCanvas* c2 = i2->getFrames()[0];
return c1->collide(x1, y1, c2, x2, y2, true);
}
int bbImagesCollide(bbImage* i1, int x1, int y1, int f1, bbImage* i2, int x2, int y2, int f2)
{
debugImage(i1, f1);
debugImage(i2, f2);
gxCanvas* c1 = i1->getFrames()[f1];
gxCanvas* c2 = i2->getFrames()[f2];
return c1->collide(x1, y1, c2, x2, y2, false);
}
int bbRectsOverlap(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
{
if (x1 + w1 <= x2 || x1 >= x2 + w2 || y1 + h1 <= y2 || y1 >= y2 + h2)
return 0;
return 1;
}
int bbImageRectOverlap(bbImage* i, int x, int y, int x2, int y2, int w2, int h2)
{
debugImage(i);
gxCanvas* c = i->getFrames()[0];
return c->rect_collide(x, y, x2, y2, w2, h2, true);
}
int bbImageRectCollide(bbImage* i, int x, int y, int f, int x2, int y2, int w2, int h2)
{
debugImage(i, f);
gxCanvas* c = i->getFrames()[f];
return c->rect_collide(x, y, x2, y2, w2, h2, false);
}
void bbTFormImage(bbImage* i, float a, float b, float c, float d)
{
debugImage(i);
const std::vector<gxCanvas*>& f = i->getFrames();
int k;
for (k = 0; k < f.size(); ++k) {
if (f[k] == gx_canvas) {
bbSetBuffer(gx_graphics->getFrontCanvas());
break;
}
}
float m[2][2];
m[0][0] = a;
m[1][0] = b;
m[0][1] = c;
m[1][1] = d;
for (k = 0; k < f.size(); ++k) {
gxCanvas* c = f[k];
int hx, hy;
c->getHandle(&hx, &hy);
gxCanvas* t = tformCanvas(c, m, hx, hy);
i->replaceFrame(k, t);
t->backup();
}
}
void bbScaleImage(bbImage* i, float w, float h)
{
debugImage(i);
bbTFormImage(i, w, 0, 0, h);
}
void bbResizeImage(bbImage* i, float w, float h)
{
debugImage(i);
gxCanvas* c = i->getFrames()[0];
bbTFormImage(i, w / (float)c->getWidth(), 0, 0, h / (float)c->getHeight());
}
void bbRotateImage(bbImage* i, float d)
{
debugImage(i);
d *= -s_degreesToRadians;
bbTFormImage(i, cos(d), -sin(d), sin(d), cos(d));
}
void bbTFormFilter(int enable)
{
filter = enable ? true : false;
}
static int p_ox, p_oy, p_hx, p_hy, p_vpx, p_vpy, p_vpw, p_vph;
static gxCanvas* startPrinting()
{
gxCanvas* c = gx_graphics->getFrontCanvas();
c->lock();
c->unlock();
c->getOrigin(&p_ox, &p_oy);
c->getHandle(&p_hx, &p_hy);
c->getViewport(&p_vpx, &p_vpy, &p_vpw, &p_vph);
c->setOrigin(0, 0);
c->setHandle(0, 0);
c->setViewport(0, 0, c->getWidth(), c->getHeight());
if (c != gx_canvas) {
c->setFont(curr_font);
c->setColor(curr_color);
}
int dy = curs_y + curr_font->getHeight() - c->getHeight();
if (dy > 0) {
curs_y = c->getHeight() - curr_font->getHeight();
c->blit(0, 0, c, 0, dy, c->getWidth(), c->getHeight() - dy, true);
c->setColor(curr_clsColor);
c->rect(0, c->getHeight() - dy, c->getWidth(), dy, true);
c->setColor(curr_color);
}
return c;
}
static void endPrinting(gxCanvas* c)
{
c->setViewport(p_vpx, p_vpy, p_vpw, p_vph);
c->setHandle(p_hx, p_hy);
c->setOrigin(p_ox, p_oy);
if (c == gx_canvas)
c->setColor(curr_color);
if (!gx_runtime->idle())
ThrowRuntimeException(0);
}
void bbWrite(BBStr* str)
{
gxCanvas* c = startPrinting();
c->text(curs_x, curs_y, *str);
curs_x += curr_font->getWidth(*str);
endPrinting(c);
delete str;
}
void bbPrint(BBStr* str)
{
gxCanvas* c = startPrinting();
c->text(curs_x, curs_y, *str);
curs_x = 0;
curs_y += curr_font->getHeight();
endPrinting(c);
delete str;
}
BBStr* bbInput(BBStr* prompt)
{
gxCanvas* c = startPrinting();
std::string t = *prompt;
delete prompt;
//get temp canvas
if (!p_canvas || p_canvas->getWidth() < c->getWidth() || p_canvas->getHeight() < curr_font->getHeight() * 2) {
if (p_canvas)
gx_graphics->freeCanvas(p_canvas);
p_canvas = gx_graphics->createCanvas(c->getWidth(), curr_font->getHeight() * 2, 0);
if (!p_canvas) {
endPrinting(c);
return new BBStr();
}
}
//draw prompt
c->text(curs_x, curs_y, t);
curs_x += curr_font->getWidth(t);
p_canvas->setFont(curr_font);
p_canvas->setColor(curr_color);
p_canvas->blit(0, 0, c, 0, curs_y, c->getWidth(), curr_font->getHeight(), true);
std::string str;
bool go = true;
int curs = 0, last_key = 0, last_time, rep_delay;
while (go) {
//render all text
//calc curs x and width
int cx = curs_x + curr_font->getWidth(str.substr(0, curs));
int cw = curr_font->getWidth(curs < str.size() ? str.substr(curs, 1) : "X");
//wait for a key
int key = 0, st = gx_runtime->getMilliSecs(), tc = -1;
while (gx_runtime->idle()) {
int t = gx_runtime->getMilliSecs();
int n = (t - st) / 320;
if (n != tc) {
tc = n;
if (!(tc & 1)) { //cursor ON
c->setColor(curr_clsColor ^ 0xffffff);
c->rect(cx, curs_y, cw, curr_font->getHeight(), true);
c->setColor(curr_clsColor);
} else { //cursor OFF
c->blit(cx, curs_y, p_canvas, cx, 0, cw, curr_font->getHeight(), true);
c->setColor(curr_color);
}
c->text(cx, curs_y, str.substr(curs, 1));
}
if (key = gx_keyboard->getKey()) {
if (int asc = gx_input->toAscii(key)) {
rep_delay = 280;
last_key = key;
last_time = t;
key = asc;
break;
}
}
if (last_key && gx_keyboard->keyDown(last_key)) {
if (t - last_time > rep_delay) {
if (key = gx_input->toAscii(last_key)) {
last_time += rep_delay;
rep_delay = 40;
break;
}
}
} else
last_key = 0;
gx_runtime->delay(20);
}
//check the key
switch (key) {
case 0:
go = false;
str = "";
break;
case 8:
if (curs) {
str = str.substr(0, curs - 1) + str.substr(curs);
--curs;
}
break;
case 27:
curs = 0;
str = "";
break;
case gxInput::ASC_DELETE:
if (curs < str.size())
str = str.substr(0, curs) + str.substr(curs + 1);
break;
case gxInput::ASC_HOME:
curs = 0;
break;
case gxInput::ASC_END:
curs = str.size();
break;
case gxInput::ASC_LEFT:
if (curs)
--curs;
break;
case gxInput::ASC_RIGHT:
if (curs < str.size())
++curs;
break;
case '\r':
go = false;
break;
default:
if (curr_font->isPrintable(key)) {
str = str.substr(0, curs) + char(key) + str.substr(curs);
++curs;
}
}
//render text
p_canvas->blit(0, curr_font->getHeight(), p_canvas, 0, 0, c->getWidth(), curr_font->getHeight(), true);
p_canvas->text(curs_x, curr_font->getHeight(), str);
c->blit(0, curs_y, p_canvas, 0, curr_font->getHeight(), c->getWidth(), curr_font->getHeight(), true);
}
curs_x = 0;
curs_y += curr_font->getHeight();
endPrinting(c);
return new BBStr(str);
}
void bbLocate(int x, int y)
{
gxCanvas* c = gx_graphics->getFrontCanvas();
curs_x = x < 0 ? 0 : (x > c->getWidth() ? c->getWidth() : x);
curs_y = y < 0 ? 0 : (y > c->getHeight() ? c->getHeight() : y);
}
void bbShowPointer()
{
gx_runtime->setPointerVisible(true);
}
void bbHidePointer()
{
gx_runtime->setPointerVisible(false);
}
bool graphics_create()
{
p_canvas = 0;
filter = true;
gx_driver = 0;
freeGraphics();
auto_dirty = true;
auto_midhandle = false;
gx_graphics = gx_runtime->openGraphics(400, 300, 0, 0, gxGraphics::GRAPHICS_WINDOWED);
if (gx_graphics) {
curr_clsColor = 0;
curr_color = 0xffffffff;
curr_font = gx_graphics->getDefaultFont();
bbSetBuffer(bbFrontBuffer());
return true;
}
return false;
}
bool graphics_destroy()
{
freeGraphics();
gfx_modes.clear();
if (gx_graphics) {
gx_runtime->closeGraphics(gx_graphics);
gx_graphics = 0;
}
return true;
}
void graphics_link(void (*rtSym)(const char* sym, void* pc))
{
//gfx driver info
rtSym("%CountGfxDrivers", bbCountGfxDrivers);
rtSym("$GfxDriverName%driver", bbGfxDriverName);
rtSym("SetGfxDriver%driver", bbSetGfxDriver);
//gfx mode info
rtSym("%CountGfxModes", bbCountGfxModes);
rtSym("%GfxModeExists%width%height%depth", bbGfxModeExists);
rtSym("%GfxModeWidth%mode", bbGfxModeWidth);
rtSym("%GfxModeHeight%mode", bbGfxModeHeight);
rtSym("%GfxModeDepth%mode", bbGfxModeDepth);
rtSym("%AvailVidMem", bbAvailVidMem);
rtSym("%TotalVidMem", bbTotalVidMem);
rtSym("%GfxDriver3D%driver", bbGfxDriver3D);
rtSym("%CountGfxModes3D", bbCountGfxModes3D);
rtSym("%GfxMode3DExists%width%height%depth", bbGfxMode3DExists);
rtSym("%GfxMode3D%mode", bbGfxMode3D);
rtSym("%Windowed3D", bbWindowed3D);
//display mode
// rtSym( "Graphics%width%height%depth=0%mode=0",bbGraphics );
rtSym("Graphics3D%width%height%depth=0%mode=0", bbGraphics3D);
rtSym("EndGraphics", bbEndGraphics);
rtSym("%GraphicsLost", bbGraphicsLost);
rtSym("SetGamma%src_red%src_green%src_blue#dest_red#dest_green#dest_blue", bbSetGamma);
rtSym("UpdateGamma%calibrate=0", bbUpdateGamma);
rtSym("#GammaRed%red", bbGammaRed);
rtSym("#GammaGreen%green", bbGammaGreen);
rtSym("#GammaBlue%blue", bbGammaBlue);
rtSym("%FrontBuffer", bbFrontBuffer);
rtSym("%BackBuffer", bbBackBuffer);
rtSym("%ScanLine", bbScanLine);
rtSym("VWait%frames=1", bbVWait);
rtSym("Flip%vwait=1", bbFlip);
rtSym("%GraphicsWidth", bbGraphicsWidth);
rtSym("%GraphicsHeight", bbGraphicsHeight);
rtSym("%GraphicsDepth", bbGraphicsDepth);
//buffer management
rtSym("SetBuffer%buffer", bbSetBuffer);
rtSym("%GraphicsBuffer", bbGraphicsBuffer);
rtSym("%LoadBuffer%buffer$bmpfile", bbLoadBuffer);
rtSym("%SaveBuffer%buffer$bmpfile", bbSaveBuffer);
rtSym("BufferDirty%buffer", bbBufferDirty);
//fast pixel reads/write
rtSym("LockBuffer%buffer=0", bbLockBuffer);
rtSym("UnlockBuffer%buffer=0", bbUnlockBuffer);
rtSym("%ReadPixel%x%y%buffer=0", bbReadPixel);
rtSym("WritePixel%x%y%argb%buffer=0", bbWritePixel);
rtSym("%ReadPixelFast%x%y%buffer=0", bbReadPixelFast);
rtSym("WritePixelFast%x%y%argb%buffer=0", bbWritePixelFast);
rtSym("CopyPixel%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0", bbCopyPixel);
rtSym("CopyPixelFast%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0", bbCopyPixelFast);
//rendering
rtSym("Origin%x%y", bbOrigin);
rtSym("Viewport%x%y%width%height", bbViewport);
rtSym("Color%red%green%blue", bbColor);
rtSym("GetColor%x%y", bbGetColor);
rtSym("%ColorRed", bbColorRed);
rtSym("%ColorGreen", bbColorGreen);
rtSym("%ColorBlue", bbColorBlue);
rtSym("ClsColor%red%green%blue", bbClsColor);
rtSym("SetFont%font", bbSetFont);
rtSym("Cls", bbCls);
rtSym("Plot%x%y", bbPlot);
rtSym("Rect%x%y%width%height%solid=1", bbRect);
rtSym("Oval%x%y%width%height%solid=1", bbOval);
rtSym("Line%x1%y1%x2%y2", bbLine);
rtSym("Text%x%y$text%centre_x=0%centre_y=0", bbText);
rtSym("CopyRect%source_x%source_y%width%height%dest_x%dest_y%src_buffer=0%dest_buffer=0", bbCopyRect);
//fonts
rtSym("%LoadFont$fontname%height=12%bold=0%italic=0%underline=0", bbLoadFont);
rtSym("FreeFont%font", bbFreeFont);
rtSym("%FontWidth", bbFontWidth);
rtSym("%FontHeight", bbFontHeight);
rtSym("%StringWidth$string", bbStringWidth);
rtSym("%StringHeight$string", bbStringHeight);
//movies
rtSym("%OpenMovie$file", bbOpenMovie);
rtSym("%DrawMovie%movie%x=0%y=0%w=-1%h=-1", bbDrawMovie);
rtSym("%MovieWidth%movie", bbMovieWidth);
rtSym("%MovieHeight%movie", bbMovieHeight);
rtSym("%MoviePlaying%movie", bbMoviePlaying);
rtSym("CloseMovie%movie", bbCloseMovie);
rtSym("%LoadImage$bmpfile", bbLoadImage);
rtSym("%LoadAnimImage$bmpfile%cellwidth%cellheight%first%count", bbLoadAnimImage);
rtSym("%CopyImage%image", bbCopyImage);
rtSym("%CreateImage%width%height%frames=1", bbCreateImage);
rtSym("FreeImage%image", bbFreeImage);
rtSym("%SaveImage%image$bmpfile%frame=0", bbSaveImage);
rtSym("GrabImage%image%x%y%frame=0", bbGrabImage);
rtSym("%ImageBuffer%image%frame=0", bbImageBuffer);
rtSym("DrawImage%image%x%y%frame=0", bbDrawImage);
rtSym("DrawBlock%image%x%y%frame=0", bbDrawBlock);
rtSym("TileImage%image%x=0%y=0%frame=0", bbTileImage);
rtSym("TileBlock%image%x=0%y=0%frame=0", bbTileBlock);
rtSym("DrawImageRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0", bbDrawImageRect);
rtSym("DrawBlockRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0", bbDrawBlockRect);
rtSym("MaskImage%image%red%green%blue", bbMaskImage);
rtSym("HandleImage%image%x%y", bbHandleImage);
rtSym("MidHandle%image", bbMidHandle);
rtSym("AutoMidHandle%enable", bbAutoMidHandle);
rtSym("%ImageWidth%image", bbImageWidth);
rtSym("%ImageHeight%image", bbImageHeight);
rtSym("%ImageXHandle%image", bbImageXHandle);
rtSym("%ImageYHandle%image", bbImageYHandle);
rtSym("ScaleImage%image#xscale#yscale", bbScaleImage);
rtSym("ResizeImage%image#width#height", bbResizeImage);
rtSym("RotateImage%image#angle", bbRotateImage);
rtSym("TFormImage%image#a#b#c#d", bbTFormImage);
rtSym("TFormFilter%enable", bbTFormFilter);
rtSym("%ImagesOverlap%image1%x1%y1%image2%x2%y2", bbImagesOverlap);
rtSym("%ImagesCollide%image1%x1%y1%frame1%image2%x2%y2%frame2", bbImagesCollide);
rtSym("%RectsOverlap%x1%y1%width1%height1%x2%y2%width2%height2", bbRectsOverlap);
rtSym("%ImageRectOverlap%image%x%y%rect_x%rect_y%rect_width%rect_height", bbImageRectOverlap);
rtSym("%ImageRectCollide%image%x%y%frame%rect_x%rect_y%rect_width%rect_height", bbImageRectCollide);
rtSym("Write$string", bbWrite);
rtSym("Print$string=\"\"", bbPrint);
rtSym("$Input$prompt=\"\"", bbInput);
rtSym("Locate%x%y", bbLocate);
rtSym("ShowPointer", bbShowPointer);
rtSym("HidePointer", bbHidePointer);
}
// NVidia Optimus
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}