// Z buffer: 16,32 bits Z / 16 bits color #include "common/scummsys.h" #include "common/endian.h" #include "graphics/tinygl/zbuffer.h" #include "graphics/tinygl/zgl.h" namespace TinyGL { uint8 PSZB; ZBuffer *ZB_open(int xsize, int ysize, const Graphics::PixelBuffer &frame_buffer) { ZBuffer *zb; int size; zb = (ZBuffer *)gl_malloc(sizeof(ZBuffer)); if (!zb) return NULL; zb->xsize = xsize; zb->ysize = ysize; zb->cmode = frame_buffer.getFormat(); PSZB = zb->pixelbytes = zb->cmode.bytesPerPixel; zb->pixelbits = zb->cmode.bytesPerPixel * 8; zb->linesize = (xsize * zb->pixelbytes + 3) & ~3; size = zb->xsize * zb->ysize * sizeof(unsigned int); zb->zbuf = (unsigned int *)gl_malloc(size); if (!zb->zbuf) goto error; if (!frame_buffer) { byte *pbuf = (byte *)gl_malloc(zb->ysize * zb->linesize); if (!pbuf) { gl_free(zb->zbuf); goto error; } zb->pbuf.set(zb->cmode, pbuf); zb->frame_buffer_allocated = 1; } else { zb->frame_buffer_allocated = 0; zb->pbuf = frame_buffer; } zb->current_texture = NULL; zb->shadow_mask_buf = NULL; zb->buffers[0].pbuf = zb->pbuf.getRawBuffer(); zb->buffers[0].zbuf = zb->zbuf; zb->buffers[1].pbuf = NULL; zb->buffers[1].zbuf = NULL; zb->buffers[1].used = false; return zb; error: gl_free(zb); return NULL; } void ZB_close(ZBuffer *zb) { if (zb->frame_buffer_allocated) zb->pbuf.free(); gl_free(zb->zbuf); gl_free(zb->buffers[1].pbuf); gl_free(zb->buffers[1].zbuf); gl_free(zb); } void ZB_resize(ZBuffer *zb, void *frame_buffer, int xsize, int ysize) { int size; // xsize must be a multiple of 4 xsize = xsize & ~3; zb->xsize = xsize; zb->ysize = ysize; zb->linesize = (xsize * zb->pixelbytes + 3) & ~3; size = zb->xsize * zb->ysize * sizeof(unsigned int); gl_free(zb->zbuf); zb->zbuf = (unsigned int *)gl_malloc(size); if (zb->frame_buffer_allocated) zb->pbuf.free(); if (!frame_buffer) { byte *pbuf = (byte *)gl_malloc(zb->ysize * zb->linesize); zb->pbuf.set(zb->cmode, pbuf); zb->frame_buffer_allocated = 1; } else { zb->pbuf = (byte *)frame_buffer; zb->frame_buffer_allocated = 0; } } static void ZB_copyBuffer(ZBuffer *zb, void *buf, int linesize) { unsigned char *p1; byte *q; int y, n; q = zb->pbuf.getRawBuffer(); p1 = (unsigned char *)buf; n = zb->xsize * zb->pixelbytes; for (y = 0; y < zb->ysize; y++) { memcpy(p1, q, n); p1 += linesize; q = q + zb->linesize; } } void ZB_copyFrameBuffer(ZBuffer *zb, void *buf, int linesize) { ZB_copyBuffer(zb, buf, linesize); } // adr must be aligned on an 'int' void memset_s(void *adr, int val, int count) { int i, n, v; unsigned int *p; unsigned short *q; p = (unsigned int *)adr; v = val | (val << 16); n = count >> 3; for (i = 0; i < n; i++) { p[0] = v; p[1] = v; p[2] = v; p[3] = v; p += 4; } q = (unsigned short *) p; n = count & 7; for (i = 0; i < n; i++) *q++ = val; } void memset_l(void *adr, int val, int count) { int i, n, v; unsigned int *p; p = (unsigned int *)adr; v = val; n = count >> 2; for (i = 0; i < n; i++) { p[0] = v; p[1] = v; p[2] = v; p[3] = v; p += 4; } n = count & 3; for (i = 0; i < n; i++) *p++ = val; } void ZB_clear(ZBuffer *zb, int clear_z, int z, int clear_color, int r, int g, int b) { uint32 color; int y; byte *pp; if (clear_z) { memset_l(zb->zbuf, z, zb->xsize * zb->ysize); } if (clear_color) { pp = zb->pbuf.getRawBuffer(); for (y = 0; y < zb->ysize; y++) { color = zb->cmode.RGBToColor(r, g, b); memset_s(pp, color, zb->xsize); pp = pp + zb->linesize; } } } void ZB_selectScreenBuffer(ZBuffer *zb) { zb->pbuf = zb->buffers[0].pbuf; zb->zbuf = zb->buffers[0].zbuf; } void ZB_selectOffscreenBuffer(ZBuffer *zb) { Buffer &buf = zb->buffers[1]; if (!buf.pbuf) { buf.pbuf = (byte *)gl_malloc(zb->ysize * zb->linesize); int size = zb->xsize * zb->ysize * sizeof(unsigned int); buf.zbuf = (unsigned int *)gl_malloc(size); } zb->pbuf = buf.pbuf; zb->zbuf = buf.zbuf; buf.used = true; } void ZB_blitOffscreenBuffer(ZBuffer *zb) { // TODO: could be faster, probably. Buffer &buf = zb->buffers[1]; if (buf.used) { for (int i = 0; i < zb->xsize * zb->ysize; ++i) { unsigned int d1 = buf.zbuf[i]; unsigned int d2 = zb->buffers[0].zbuf[i]; if (d1 > d2) { const int offset = i * PSZB; memcpy(zb->buffers[0].pbuf + offset, buf.pbuf + offset, PSZB); } } } } void ZB_clearOffscreenBuffer(ZBuffer *zb) { Buffer &buf = zb->buffers[1]; if (buf.pbuf) { memset(buf.pbuf, 0, zb->ysize * zb->linesize); memset(buf.zbuf, 0, zb->ysize * zb->xsize * sizeof(unsigned int)); buf.used = false; } } } // end of namespace TinyGL