Files
BlitzNext/gxruntime/gxcanvas.cpp
T
Michael Fabian Dirks 581c640149 Uh, Updates?
2016-10-03 17:11:15 +02:00

725 lines
20 KiB
C++

#include "std.h"
#include "gxcanvas.h"
#include "gxgraphics.h"
#include "gxruntime.h"
#include "asmcoder.h"
#define DEBUG_BITMASK
static int canvas_cnt;
static DDBLTFX bltfx = { sizeof(DDBLTFX) };
extern gxRuntime *gx_runtime;
static unsigned FWMS[] = {
0xffffffff,0x7fffffff,0x3fffffff,0x1fffffff,
0x0fffffff,0x07ffffff,0x03ffffff,0x01ffffff,
0x00ffffff,0x007fffff,0x003fffff,0x001fffff,
0x000fffff,0x0007ffff,0x0003ffff,0x0001ffff,
0x0000ffff,0x00007fff,0x00003fff,0x00001fff,
0x00000fff,0x000007ff,0x000003ff,0x000001ff,
0x000000ff,0x0000007f,0x0000003f,0x0000001f,
0x0000000f,0x00000007,0x00000003,0x00000001 };
static unsigned LWMS[] = {
0x80000000,0xc0000000,0xe0000000,0xf0000000,
0xf8000000,0xfc000000,0xfe000000,0xff000000,
0xff800000,0xffc00000,0xffe00000,0xfff00000,
0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,
0xffff8000,0xffffc000,0xffffe000,0xfffff000,
0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,
0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0,
0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff };
static void calcShifts(unsigned mask, unsigned char *shr, unsigned char *shl) {
if (mask) {
for (*shl = 0; !(mask & 1); ++*shl, mask >>= 1) {}
for (*shr = 8; mask & 1; --*shr, mask >>= 1) {}
} else *shr = *shl = 0;
}
struct Rect : public RECT {
Rect() {}
Rect(int x, int y, int w, int h) {
left = x; top = y; right = x + w; bottom = y + h;
}
};
static bool clip(const RECT &viewport, RECT *d) {
if (d->right <= d->left ||
d->bottom <= d->top ||
d->left >= viewport.right ||
d->right <= viewport.left ||
d->top >= viewport.bottom ||
d->bottom <= viewport.top) return false;
if (d->left < viewport.left) d->left = viewport.left;
if (d->right > viewport.right) d->right = viewport.right;
if (d->top < viewport.top) d->top = viewport.top;
if (d->bottom > viewport.bottom) d->bottom = viewport.bottom;
return true;
}
static bool clip(const RECT &viewport, RECT *d, RECT *s) {
if (d->right <= d->left ||
d->bottom <= d->top ||
d->left >= viewport.right ||
d->right <= viewport.left ||
d->top >= viewport.bottom ||
d->bottom <= viewport.top) return false;
int dx, dy;
if ((dx = viewport.left - d->left) > 0) { d->left += dx; s->left += dx; }
if ((dx = viewport.right - d->right) < 0) { d->right += dx; s->right += dx; }
if ((dy = viewport.top - d->top) > 0) { d->top += dy; s->top += dy; }
if ((dy = viewport.bottom - d->bottom) < 0) { d->bottom += dy; s->bottom += dy; }
return true;
}
gxCanvas::gxCanvas(gxGraphics *g, IDirectDrawSurface7 *s, int f) :
graphics(g), main_surf(s), surf(0), z_surf(0), flags(f), cube_mode(CUBEMODE_REFLECTION | CUBESPACE_WORLD),
t_surf(0), cm_mask(0), locked_cnt(0), mod_cnt(0), remip_cnt(0) {
if (flags & CANVAS_TEX_CUBE) {
cube_surfs[2] = main_surf;
for (int k = 0; k < 6; ++k) {
if (k == 2) continue;
DWORD n;
switch (k) {
case 0:n = DDSCAPS2_CUBEMAP_NEGATIVEX; break;
case 1:n = DDSCAPS2_CUBEMAP_POSITIVEZ; break;
case 2:n = DDSCAPS2_CUBEMAP_POSITIVEX; break;
case 3:n = DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
case 4:n = DDSCAPS2_CUBEMAP_POSITIVEY; break;
case 5:n = DDSCAPS2_CUBEMAP_NEGATIVEY; break;
default:return;
}
DDSCAPS2 caps = { 0 };
caps.dwCaps2 = DDSCAPS2_CUBEMAP | n;
main_surf->GetAttachedSurface(&caps, &cube_surfs[k]);
}
surf = cube_surfs[1];
} else {
surf = main_surf;
memset(cube_surfs, 0, sizeof(cube_surfs));
}
DDSURFACEDESC2 desc = { sizeof(desc) };
surf->GetSurfaceDesc(&desc);
format.setFormat(desc.ddpfPixelFormat);
clip_rect.left = clip_rect.top = 0;
clip_rect.right = desc.dwWidth;
clip_rect.bottom = desc.dwHeight;
cm_pitch = (clip_rect.right + 31) / 32 + 1;
setMask(0);
setColor(~0);
setClsColor(0);
setOrigin(0, 0);
setHandle(0, 0);
setFont(graphics->getDefaultFont());
setViewport(0, 0, getWidth(), getHeight());
if (flags & gxCanvas::CANVAS_TEXTURE) ddUtil::buildMipMaps(surf);
}
gxCanvas::~gxCanvas() {
delete[] cm_mask;
if (locked_cnt) surf->Unlock(0);
if (t_surf) t_surf->Release();
releaseZBuffer();
main_surf->Release();
}
void gxCanvas::backup()const {
if (flags & CANVAS_TEX_CUBE) return;
if (!t_surf) {
DDSURFACEDESC2 desc = { sizeof(desc) };
if (surf->GetSurfaceDesc(&desc) < 0) return;
if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) return;
DDSURFACEDESC2 t_desc = { sizeof(t_desc) };
t_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
t_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
t_desc.dwWidth = desc.dwWidth; t_desc.dwHeight = desc.dwHeight;
t_desc.ddpfPixelFormat = desc.ddpfPixelFormat;
if (graphics->dirDraw->CreateSurface(&t_desc, &t_surf, 0) < 0) {
t_surf = 0;
return;
}
}
if (t_surf->Blt(0, surf, 0, DDBLT_WAIT, 0) < 0) return;
}
void gxCanvas::restore()const {
if (!t_surf) return;
if (surf->Blt(0, t_surf, 0, DDBLT_WAIT, 0) < 0) return;
}
ddSurf *gxCanvas::getSurface()const {
return surf;
}
ddSurf *gxCanvas::getTexSurface()const {
if (mod_cnt == remip_cnt) return main_surf;
ddUtil::buildMipMaps(surf);
remip_cnt = mod_cnt;
return main_surf;
}
bool gxCanvas::clip(RECT *d)const {
return ::clip(viewport, d);
}
bool gxCanvas::clip(RECT *d, RECT *s)const {
return ::clip(viewport, d, s);
}
void gxCanvas::updateBitMask(const RECT &r)const {
int w = r.right - r.left; if (w <= 0) return;
int h = r.bottom - r.top; if (h <= 0) return;
lock();
RECT t = r;
t.left &= ~31;
t.right = (t.right + 31)&~31;
w = (t.right - t.left) / 32;
unsigned char *src_row = locked_surf + t.top*locked_pitch + t.left*format.getPitch();
unsigned *dest_row = cm_mask + t.top*cm_pitch + t.left / 32;
unsigned mask_argb = format.toARGB(mask_surf) & 0xffffff;
#ifdef DEBUG_BITMASK
unsigned *cm_mask_end = cm_mask + cm_pitch*clip_rect.bottom;
#endif
while (h--) {
unsigned *dest = dest_row;
unsigned char *src = src_row;
for (int c = 0; c < w; ++c) {
unsigned mask = 0;
for (int x = 0; x < 32; ++x) {
unsigned pix = format.getPixel(src) & 0xffffff;
mask = (mask << 1) | (pix != mask_argb);
src += format.getPitch();
}
#ifdef DEBUG_BITMASK
if (dest < cm_mask || dest >= cm_mask_end) {
gx_runtime->debugError("gxCanvas::updateBitMask dest out of range");
}
#endif
*dest++ = mask;
}
dest_row += cm_pitch;
src_row += locked_pitch;
}
unlock();
}
void gxCanvas::setModify(int n) {
mod_cnt = n;
}
int gxCanvas::getModify()const {
return mod_cnt;
}
bool gxCanvas::attachZBuffer() {
if (z_surf) return true;
DDSURFACEDESC2 desc = { sizeof(desc) };
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
desc.dwWidth = getWidth();
desc.dwHeight = getHeight();
desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
desc.ddpfPixelFormat = graphics->zbuffFmt;
if (graphics->dirDraw->CreateSurface(&desc, &z_surf, 0) < 0) return false;
surf->AddAttachedSurface(z_surf);
return true;
}
void gxCanvas::releaseZBuffer() {
if (!z_surf) return;
surf->DeleteAttachedSurface(0, z_surf);
z_surf->Release();
z_surf = 0;
}
void gxCanvas::damage(const RECT &r)const {
++mod_cnt; if (cm_mask) updateBitMask(r);
}
void gxCanvas::setFont(gxFont *f) {
font = f;
}
void gxCanvas::setMask(unsigned argb) {
mask_surf = format.fromARGB(argb);
}
void gxCanvas::setColor(unsigned argb) {
argb |= 0xff000000;
color_argb = argb;
color_surf = format.fromARGB(argb);
}
void gxCanvas::setClsColor(unsigned argb) {
argb |= 0xff000000;
clsColor_surf = format.fromARGB(argb);
}
void gxCanvas::setOrigin(int x, int y) {
origin_x = x; origin_y = y;
}
void gxCanvas::setHandle(int x, int y) {
handle_x = x; handle_y = y;
}
void gxCanvas::setViewport(int x, int y, int w, int h) {
Rect r(x, y, w, h);
if (!::clip(clip_rect, &r)) r = Rect(0, 0, 0, 0);
viewport = r;
}
//renderering primitives
void gxCanvas::cls() {
bltfx.dwFillColor = clsColor_surf;
surf->Blt(&viewport, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
damage(viewport);
}
void gxCanvas::plot(int x, int y) {
x += origin_x; if (x < viewport.left || x >= viewport.right) return;
y += origin_y; if (y < viewport.top || y >= viewport.bottom) return;
bltfx.dwFillColor = color_surf;
Rect dest(x, y, 1, 1);
surf->Blt(&dest, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
damage(dest);
}
void gxCanvas::line(int x0, int y0, int x1, int y1) {
int ddf, padj, sadj;
int dx, dy, sx, sy, ax, ay;
x0 += origin_x; y0 += origin_y;
x1 += origin_x; y1 += origin_y;
int cx0, cx1, cy0, cy1, clip0, clip1;
cx0 = viewport.left;
cx1 = viewport.right - 1;
cy0 = viewport.top;
cy1 = viewport.bottom - 1;
while (true) {
clip0 = 0; clip1 = 0;
if (y0 > cy1)clip0 |= 1; else if (y0 < cy0)clip0 |= 2;
if (x0 > cx1)clip0 |= 4; else if (x0 < cx0)clip0 |= 8;
if (y1 > cy1)clip1 |= 1; else if (y1 < cy0)clip1 |= 2;
if (x1 > cx1)clip1 |= 4; else if (x1 < cx0)clip1 |= 8;
if ((clip0 | clip1) == 0) break; //draw line
if ((clip0&clip1) != 0) return; //outside
if ((clip0 & 1) == 1) { x0 = x0 + ((x1 - x0)*(cy1 - y0)) / (y1 - y0); y0 = cy1; continue; }
if ((clip0 & 2) == 2) { x0 = x0 + ((x1 - x0)*(cy0 - y0)) / (y1 - y0); y0 = cy0; continue; }
if ((clip0 & 4) == 4) { y0 = y0 + ((y1 - y0)*(cx1 - x0)) / (x1 - x0); x0 = cx1; continue; }
if ((clip0 & 8) == 8) { y0 = y0 + ((y1 - y0)*(cx0 - x0)) / (x1 - x0); x0 = cx0; continue; }
if ((clip1 & 1) == 1) { x1 = x0 + ((x1 - x0)*(cy1 - y0)) / (y1 - y0); y1 = cy1; continue; }
if ((clip1 & 2) == 2) { x1 = x0 + ((x1 - x0)*(cy0 - y0)) / (y1 - y0); y1 = cy0; continue; }
if ((clip1 & 4) == 4) { y1 = y0 + ((y1 - y0)*(cx1 - x0)) / (x1 - x0); x1 = cx1; continue; }
if ((clip1 & 8) == 8) { y1 = y0 + ((y1 - y0)*(cx0 - x0)) / (x1 - x0); x1 = cx0; continue; }
}
dx = x1 - x0; dy = y1 - y0;
if ((dx | dy) == 0) {
setPixel(x0, y0, color_argb);
return;
}
if (dx >= 0) { sx = 1; ax = dx; } else { sx = -1; ax = -dx; }
if (dy >= 0) { sy = 1; ay = dy; } else { sy = -1; ay = -dy; }
lock();
if (ax > ay) {
ddf = -ax; sadj = ax + ax; padj = ay + ay;
while (ax-- >= 0) {
setPixelFast(x0, y0, color_argb);
x0 += sx; ddf += padj; if (ddf >= 0) { y0 += sy; ddf -= sadj; }
}
} else {
ddf = -ay; sadj = ay + ay; padj = ax + ax;
while (ay-- >= 0) {
setPixelFast(x0, y0, color_argb);
y0 += sy; ddf += padj; if (ddf >= 0) { x0 += sx; ddf -= sadj; }
}
}
unlock();
}
void gxCanvas::rect(int x, int y, int w, int h, bool solid) {
x += origin_x; y += origin_y;
Rect dest(x, y, w, h);
if (!clip(&dest)) return;
bltfx.dwFillColor = color_surf;
if (solid) {
surf->Blt(&dest, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
damage(dest);
return;
}
Rect r1(x, y, w, 1); if (clip(&r1)) {
surf->Blt(&r1, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
Rect r2(x, y, 1, h); if (clip(&r2)) {
surf->Blt(&r2, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
Rect r3(x + w - 1, y, 1, h); if (clip(&r3)) {
surf->Blt(&r3, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
Rect r4(x, y + h - 1, w, 1); if (clip(&r4)) {
surf->Blt(&r4, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
damage(dest);
}
void gxCanvas::oval(int x1, int y1, int w, int h, bool solid) {
x1 += origin_x; y1 += origin_y;
Rect dest(x1, y1, w, h);
if (!clip(&dest)) return;
bltfx.dwFillColor = color_surf;
float xr = w*.5f, yr = h*.5f, ar = (float)w / (float)h;
float cx = x1 + xr + .5f, cy = y1 + yr - .5f, rsq = yr*yr, y;
if (solid) {
y = dest.top - cy;
for (int t = dest.top; t < dest.bottom; ++y, ++t) {
float x = sqrt(rsq - y*y)*ar;
int xa = floor(cx - x), xb = floor(cx + x);
if (xb <= xa || xa >= viewport.right || xb <= viewport.left) continue;
Rect dr; dr.top = t; dr.bottom = t + 1;
dr.left = xa < viewport.left ? viewport.left : xa;
dr.right = xb > viewport.right ? viewport.right : xb;
surf->Blt(&dr, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
damage(dest);
return;
}
int p_xa, p_xb, t, hh = floor(cy);
p_xa = p_xb = cx;
t = dest.top; y = t - cy;
if (dest.top > y1) { --t; --y; }
for (; t <= hh; ++y, ++t) {
float x = sqrt(rsq - y*y)*ar;
int xa = floor(cx - x), xb = floor(cx + x);
Rect r1(xa, t, p_xa - xa, 1); if (r1.right <= r1.left) r1.right = r1.left + 1;
if (clip(&r1)) surf->Blt(&r1, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
Rect r2(p_xb, t, xb - p_xb, 1); if (r2.left >= r2.right) r2.left = r2.right - 1;
if (clip(&r2)) surf->Blt(&r2, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
p_xa = xa; p_xb = xb;
}
p_xa = p_xb = cx;
t = dest.bottom - 1; y = t - cy;
if (dest.bottom < y1 + h) { ++t; ++y; }
for (; t > hh; --y, --t) {
float x = sqrt(rsq - y*y)*ar;
int xa = floor(cx - x), xb = floor(cx + x);
Rect r1(xa, t, p_xa - xa, 1); if (r1.right <= r1.left) r1.right = r1.left + 1;
if (clip(&r1)) surf->Blt(&r1, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
Rect r2(p_xb, t, xb - p_xb, 1); if (r2.left >= r2.right) r2.left = r2.right - 1;
if (clip(&r2)) surf->Blt(&r2, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
p_xa = xa; p_xb = xb;
}
damage(dest);
}
void gxCanvas::blit(int x, int y, gxCanvas *src, int src_x, int src_y, int src_w, int src_h, bool solid) {
x += origin_x - src->handle_x;
y += origin_y - src->handle_y;
Rect dest_r(x, y, src_w, src_h), src_r(src_x, src_y, src_w, src_h);
if (!clip(&dest_r, &src_r)) return;
if (!::clip(src->clip_rect, &src_r, &dest_r)) return;
if (solid) {
surf->Blt(&dest_r, src->surf, &src_r, DDBLT_WAIT, 0);
} else {
bltfx.ddckSrcColorkey.dwColorSpaceLowValue =
bltfx.ddckSrcColorkey.dwColorSpaceHighValue = src->mask_surf;
surf->Blt(&dest_r, src->surf, &src_r, DDBLT_WAIT | DDBLT_KEYSRCOVERRIDE, &bltfx);
}
damage(dest_r);
}
void gxCanvas::text(int x, int y, const string &t) {
int ty = y + origin_y;
if (ty >= viewport.bottom) return;
if (ty + font->getHeight() <= viewport.top) return;
int tx = x + origin_x;
if (tx >= viewport.right) return;
int b = 0, w;
while (b < t.size() && tx + (w = font->charWidth(t[b])) <= viewport.left) {
tx += w; x += w; ++b;
}
int e = b;
while (e < t.size() && tx < viewport.right) {
tx += font->charWidth(t[e]); ++e;
}
if (e > b) font->render(this, format.toARGB(color_surf), x, y, t.substr(b, e - b));
}
int gxCanvas::getWidth()const {
return clip_rect.right;
}
int gxCanvas::getHeight()const {
return clip_rect.bottom;
}
int gxCanvas::getDepth()const {
return format.getDepth();
}
void gxCanvas::getOrigin(int *x, int *y)const {
*x = origin_x; *y = origin_y;
}
void gxCanvas::getHandle(int *x, int *y)const {
*x = handle_x; *y = handle_y;
}
void gxCanvas::getViewport(int *x, int *y, int *w, int *h)const {
*x = viewport.left; *y = viewport.top;
*w = viewport.right - viewport.left; *h = viewport.bottom - viewport.top;
}
unsigned gxCanvas::getMask()const {
return format.toARGB(mask_surf);
}
unsigned gxCanvas::getColor()const {
return format.toARGB(color_surf);
}
unsigned gxCanvas::getClsColor()const {
return format.toARGB(clsColor_surf);
}
bool gxCanvas::collide(int x1, int y1, const gxCanvas *i2, int x2, int y2, bool solid)const {
x1 -= handle_x; x2 -= i2->handle_x;
if (x1 + clip_rect.right <= x2 || x1 >= x2 + i2->clip_rect.right) return false;
y1 -= handle_y; y2 -= i2->handle_y;
if (y1 + clip_rect.bottom <= y2 || y1 >= y2 + i2->clip_rect.bottom) return false;
if (solid) return true;
if (!cm_mask) {
cm_mask = new unsigned[cm_pitch*clip_rect.bottom];
updateBitMask(clip_rect);
}
if (!i2->cm_mask) {
i2->cm_mask = new unsigned[i2->cm_pitch*i2->clip_rect.bottom];
i2->updateBitMask(i2->clip_rect);
}
const gxCanvas *i1 = this;
//to keep me sane!
if (x1 > x2) {
std::swap(x1, x2);
std::swap(y1, y2);
std::swap(i1, i2);
}
Rect r1, r2, ir;
r1.left = x1; r1.top = y1; r1.right = x1 + i1->clip_rect.right; r1.bottom = y1 + i1->clip_rect.bottom;
r2.left = x2; r2.top = y2; r2.right = x2 + i2->clip_rect.right; r2.bottom = y2 + i2->clip_rect.bottom;
ir.left = r1.left > r2.left ? r1.left : r2.left;
ir.right = r1.right < r2.right ? r1.right : r2.right;
ir.top = r1.top > r2.top ? r1.top : r2.top;
ir.bottom = r1.bottom < r2.bottom ? r1.bottom : r2.bottom;
unsigned *s1 = i1->cm_mask, *s2 = i2->cm_mask;
int i1_pitch = i1->cm_pitch, i2_pitch = i2->cm_pitch;
s1 += (ir.top - r1.top)*i1_pitch;
s2 += (ir.top - r2.top)*i2_pitch;
int startx = ir.left - r1.left;
int stopx = ir.right - r1.left - 1;
int shr = startx & 31;
int shl = 32 - shr;
int cnt = stopx / 32 - startx / 32;
unsigned lwm = LWMS[stopx & 31];
#ifdef DEBUG_BITMASK
unsigned *cm_mask_end1 = i1->cm_mask + i1_pitch*i1->clip_rect.bottom;
unsigned *cm_mask_end2 = i2->cm_mask + i2_pitch*i2->clip_rect.bottom;
#endif
s1 += startx / 32;
for (int y = ir.top; y < ir.bottom; ++y) {
unsigned p = 0;
unsigned *row1 = s1, *row2 = s2;
for (int x = 0; x < cnt; ++x) {
#ifdef DEBUG_BITMASK
if (row1 < i1->cm_mask || row2 < i2->cm_mask) {
gx_runtime->debugError("gxCanvas::collide row underflow");
}
if (row1 >= cm_mask_end1 || row2 >= cm_mask_end2) {
gx_runtime->debugError("gxCanvas::collide row overflow");
}
#endif
unsigned n = *row2++;
if (((n >> shr) | p) & *row1++) return true;
p = shl < 32 ? n << shl : 0;
}
#ifdef DEBUG_BITMASK
if (row1 < i1->cm_mask || row2 < i2->cm_mask) {
gx_runtime->debugError("gxCanvas::collide row underflow");
}
if (row1 >= cm_mask_end1 || row2 >= cm_mask_end2) {
gx_runtime->debugError("gxCanvas::collide row overflow");
}
#endif
if (((*row2 >> shr) | p) & *row1 & lwm) return true;
s1 += i1_pitch; s2 += i2_pitch;
}
return false;
}
bool gxCanvas::rect_collide(int x1, int y1, int x2, int y2, int w2, int h2, bool solid)const {
x1 -= handle_x; if (x1 + clip_rect.right <= x2 || x1 >= x2 + w2) return false;
y1 -= handle_y; if (y1 + clip_rect.bottom <= y2 || y1 >= y2 + h2) return false;
if (solid) return true;
Rect r1(x1, y1, clip_rect.right, clip_rect.bottom), r2(x2, y2, w2, h2), ir;
ir.left = r1.left > r2.left ? r1.left : r2.left;
ir.right = r1.right < r2.right ? r1.right : r2.right;
ir.top = r1.top > r2.top ? r1.top : r2.top;
ir.bottom = r1.bottom < r2.bottom ? r1.bottom : r2.bottom;
if (!cm_mask) {
cm_mask = new unsigned[cm_pitch*clip_rect.bottom];
updateBitMask(clip_rect);
}
unsigned *s1 = cm_mask + (ir.top - r1.top)*cm_pitch;
int startx = ir.left - r1.left;
int stopx = ir.right - r1.left - 1;
int cnt = stopx / 32 - startx / 32;
unsigned fwm = FWMS[startx & 31];
unsigned lwm = LWMS[stopx & 31];
if (!cnt) { fwm &= lwm; lwm = 0; }
s1 += startx / 32;
for (int h = ir.top; h < ir.bottom; ++h) {
unsigned *row = s1;
if (*row & fwm) return true;
for (int x = 1; x < cnt; ++x) {
if (*++row) return true;
}
if (lwm && (*++row & lwm)) return true;
s1 += cm_pitch;
}
return false;
}
bool gxCanvas::lock()const {
if (!locked_cnt++) {
DDSURFACEDESC2 desc = { sizeof(desc) };
if (surf->Lock(0, &desc, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0) < 0) {
--locked_cnt;
return false;
}
locked_pitch = desc.lPitch;
locked_surf = (unsigned char*)desc.lpSurface;
lock_mod_cnt = mod_cnt;
}
return true;
}
void gxCanvas::unlock()const {
if (locked_cnt == 1) {
if (lock_mod_cnt != mod_cnt && cm_mask) updateBitMask(clip_rect);
surf->Unlock(0);
}
--locked_cnt;
}
void gxCanvas::setPixel(int x, int y, unsigned argb) {
x += origin_x; if (x < viewport.left || x >= viewport.right) return;
y += origin_y; if (y < viewport.top || y >= viewport.bottom) return;
//lock();
setPixelFast(x, y, argb);
//unlock();
}
unsigned gxCanvas::getPixel(int x, int y)const {
x += origin_x; if (x < viewport.left || x >= viewport.right) return format.toARGB(mask_surf);
y += origin_y; if (y < viewport.top || y >= viewport.bottom) return format.toARGB(mask_surf);
//lock();
unsigned p = getPixelFast(x, y);
//unlock();
return p;
}
void gxCanvas::copyPixelFast(int x, int y, gxCanvas *src, int src_x, int src_y) {
switch (format.getDepth()) {
case 16:
*(short*)(locked_surf + y*locked_pitch + x * 2) =
*(short*)(src->locked_surf + src_y*src->locked_pitch + src_x * 2);
break;
case 24:
{
unsigned char *p = locked_surf + y*locked_pitch + x * 3;
unsigned char *t = src->locked_surf + src_y*src->locked_pitch + src_x * 3;
*(short*)p = *(short*)t; *(char*)(p + 2) = *(char*)(t + 2);
}
break;
case 32:
*(int*)(locked_surf + y*locked_pitch + x * 4) =
*(int*)(src->locked_surf + src_y*src->locked_pitch + src_x * 4);
break;
}
}
void gxCanvas::copyPixel(int x, int y, gxCanvas *src, int src_x, int src_y) {
x += origin_x; if (x < viewport.left || x >= viewport.right) return;
y += origin_y; if (y < viewport.top || y >= viewport.bottom) return;
src_x += src->origin_x; if (src_x < src->viewport.left || src_x >= src->viewport.right) return;
src_y += src->origin_y; if (src_y < src->viewport.top || src_y >= src->viewport.bottom) return;
//lock();
//src->lock();
copyPixelFast(x, y, src, src_x, src_y);
//src->unlock();
//unlock();
}
void gxCanvas::setCubeMode(int mode) {
cube_mode = mode;
}
void gxCanvas::setCubeFace(int face) {
getTexSurface();
surf = cube_surfs[face];
}