Files
BlitzNext/RuntimeLib/bbgraphics.cpp
T

1364 lines
38 KiB
C++
Raw Normal View History

2016-05-07 23:09:58 +02:00
#include "std.h"
#include "bbgraphics.h"
#include "bbinput.h"
gxGraphics *gx_graphics;
gxCanvas *gx_canvas;
struct GfxMode {
int w, h, d, caps;
};
class bbImage {
public:
bbImage(const vector<gxCanvas*> &f) :frames(f) {
}
~bbImage() {
for (int k = 0; k < frames.size(); ++k) {
gx_graphics->freeCanvas(frames[k]);
}
}
const vector<gxCanvas*> &getFrames()const {
return frames;
}
void replaceFrame(int n, gxCanvas *c) {
gx_graphics->freeCanvas(frames[n]);
frames[n] = c;
}
private:
vector<gxCanvas*> frames;
};
//degrees to radians
static const float dtor = 0.0174532925199432957692369076848861f;
static int gx_driver; //current graphics driver
static bool filter;
static bool auto_dirty;
static bool auto_midhandle;
static 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 vector<GfxMode> gfx_modes;
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");
}
}
}
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 string &f) {
ofstream out(f.c_str(), 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 = d_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);
string t; int caps;
gx_runtime->graphicsDriverInfo(n - 1, &t, &caps);
return d_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);
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();
// }
2016-05-07 23:09:58 +02:00
// gx_graphics->dir3dDev->SetRenderTarget(pddsNewRenderTarget, 0);
// }
//}
}
gxCanvas *bbGraphicsBuffer() {
return gx_canvas;
}
int bbLoadBuffer(gxCanvas *c, BBStr *str) {
debugCanvas(c);
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);
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) {
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) {
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);
vector<gxCanvas*> frames;
frames.push_back(c);
bbImage *i = d_new bbImage(frames);
image_set.insert(i);
return i;
}
bbImage *bbLoadAnimImage(BBStr *s, int w, int h, int first, int cnt) {
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...
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 = d_new bbImage(frames);
image_set.insert(i);
return i;
}
bbImage *bbCopyImage(bbImage *i) {
debugImage(i);
vector<gxCanvas*> frames;
const 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 = d_new bbImage(frames);
image_set.insert(t);
return t;
}
bbImage *bbCreateImage(int w, int h, int n) {
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 = d_new bbImage(frames);
image_set.insert(i);
return i;
}
void bbFreeImage(bbImage *i) {
if (!image_set.erase(i)) return;
const 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);
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 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 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 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 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 *= -dtor;
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();
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 d_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);
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 d_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);
}