ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

zbuffer.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
00025  * which is licensed under the zlib-license (see LICENSE).
00026  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
00027  */
00028 
00029 // Z buffer: 16,32 bits Z / 16 bits color
00030 
00031 #include "common/scummsys.h"
00032 #include "common/endian.h"
00033 
00034 #include "graphics/tinygl/zbuffer.h"
00035 #include "graphics/tinygl/zgl.h"
00036 
00037 namespace TinyGL {
00038 
00039 // adr must be aligned on an 'int'
00040 void memset_s(void *adr, int val, int count) {
00041     int n, v;
00042     unsigned int *p;
00043     unsigned short *q;
00044 
00045     p = (unsigned int *)adr;
00046     v = val | (val << 16);
00047 
00048     n = count >> 3;
00049     for (int i = 0; i < n; i++) {
00050         p[0] = v;
00051         p[1] = v;
00052         p[2] = v;
00053         p[3] = v;
00054         p += 4;
00055     }
00056 
00057     q = (unsigned short *) p;
00058     n = count & 7;
00059     for (int i = 0; i < n; i++)
00060         *q++ = val;
00061 }
00062 
00063 void memset_l(void *adr, int val, int count) {
00064     int n, v;
00065     unsigned int *p;
00066 
00067     p = (unsigned int *)adr;
00068     v = val;
00069     n = count >> 2;
00070     for (int i = 0; i < n; i++) {
00071         p[0] = v;
00072         p[1] = v;
00073         p[2] = v;
00074         p[3] = v;
00075         p += 4;
00076     }
00077 
00078     n = count & 3;
00079     for (int i = 0; i < n; i++)
00080         *p++ = val;
00081 }
00082 
00083 FrameBuffer::FrameBuffer(int width, int height, const Graphics::PixelBuffer &frame_buffer) : _depthWrite(true), _enableScissor(false) {
00084     int size;
00085 
00086     this->xsize = width;
00087     this->ysize = height;
00088     this->cmode = frame_buffer.getFormat();
00089     this->pixelbytes = this->cmode.bytesPerPixel;
00090     this->linesize = (xsize * this->pixelbytes + 3) & ~3;
00091 
00092     size = this->xsize * this->ysize * sizeof(unsigned int);
00093 
00094     this->_zbuf = (unsigned int *)gl_malloc(size);
00095     memset(this->_zbuf, 0, size);
00096 
00097     if (!frame_buffer) {
00098         byte *pixelBuffer = (byte *)gl_malloc(this->ysize * this->linesize);
00099         this->pbuf.set(this->cmode, pixelBuffer);
00100         this->frame_buffer_allocated = 1;
00101     } else {
00102         this->frame_buffer_allocated = 0;
00103         this->pbuf = frame_buffer;
00104     }
00105 
00106     this->current_texture = NULL;
00107     this->shadow_mask_buf = NULL;
00108 
00109     this->buffer.pbuf = this->pbuf.getRawBuffer();
00110     this->buffer.zbuf = this->_zbuf;
00111     _blendingEnabled = false;
00112     _alphaTestEnabled = false;
00113     _depthTestEnabled = false;
00114     _depthFunc = TGL_LESS;
00115 }
00116 
00117 FrameBuffer::~FrameBuffer() {
00118     if (frame_buffer_allocated)
00119         pbuf.free();
00120     gl_free(_zbuf);
00121 }
00122 
00123 Buffer *FrameBuffer::genOffscreenBuffer() {
00124     Buffer *buf = (Buffer *)gl_malloc(sizeof(Buffer));
00125     buf->pbuf = (byte *)gl_malloc(this->ysize * this->linesize);
00126     int size = this->xsize * this->ysize * sizeof(unsigned int);
00127     buf->zbuf = (unsigned int *)gl_malloc(size);
00128 
00129     return buf;
00130 }
00131 
00132 void FrameBuffer::delOffscreenBuffer(Buffer *buf) {
00133     gl_free(buf->pbuf);
00134     gl_free(buf->zbuf);
00135     gl_free(buf);
00136 }
00137 
00138 void FrameBuffer::clear(int clearZ, int z, int clearColor, int r, int g, int b) {
00139     if (clearZ) {
00140         const uint8 *zc = (const uint8 *)&z;
00141         unsigned int i;
00142         for (i = 1; i < sizeof(z) && zc[0] == zc[i]; i++) { ; }
00143         if (i == sizeof(z)) {
00144             // All "z" bytes are identical, use memset (fast)
00145             memset(this->_zbuf, zc[0], sizeof(*this->_zbuf) * this->xsize * this->ysize);
00146         } else {
00147             // Cannot use memset, use a variant working on integers (slow)
00148             memset_l(this->_zbuf, z, this->xsize * this->ysize);
00149         }
00150     }
00151     if (clearColor) {
00152         byte *pp = this->pbuf.getRawBuffer();
00153         uint32 color = this->cmode.RGBToColor(r, g, b);
00154         const uint8 *colorc = (uint8 *)&color;
00155         unsigned int i;
00156         for (i = 1; i < sizeof(color) && colorc[0] == colorc[i]; i++) { ; }
00157         if (i == sizeof(color)) {
00158             // All "color" bytes are identical, use memset (fast)
00159             memset(pp, colorc[0], this->linesize * this->ysize);
00160         } else {
00161             // Cannot use memset, use a variant working on shorts/ints (slow)
00162             switch(this->pixelbytes) {
00163             case 2:
00164                 memset_s(pp, color, this->xsize * this->ysize);
00165                 break;
00166             case 4:
00167                 memset_l(pp, color, this->xsize * this->ysize);
00168                 break;
00169             default:
00170                 error("Unsupported pixel size %i", this->pixelbytes);
00171             }
00172         }
00173     }
00174 }
00175 
00176 void FrameBuffer::clearRegion(int x, int y, int w, int h, int clearZ, int z, int clearColor, int r, int g, int b) {
00177     if (clearZ) {
00178         int height = h;
00179         unsigned int *zbuf = this->_zbuf + (y * this->xsize);
00180         const uint8 *zc = (const uint8 *)&z;
00181         unsigned int i;
00182         for (i = 1; i < sizeof(z) && zc[0] == zc[i]; i++) { ; }
00183         if (i == sizeof(z)) {
00184             // All "z" bytes are identical, use memset (fast)
00185             while (height--) {
00186                 memset(zbuf + x, zc[0], sizeof(*zbuf) * w);
00187                 zbuf += this->xsize;
00188             }
00189         } else {
00190             // Cannot use memset, use a variant working on integers (slow)
00191             while (height--) {
00192                 memset_l(zbuf + x, z, w);
00193                 zbuf += this->xsize;
00194             }
00195         }
00196     }
00197     if (clearColor) {
00198         int height = h;
00199         byte *pp = this->pbuf.getRawBuffer() + y * this->linesize + x * this->pixelbytes;
00200         uint32 color = this->cmode.RGBToColor(r, g, b);
00201         const uint8 *colorc = (uint8 *)&color;
00202         unsigned int i;
00203         for (i = 1; i < sizeof(color) && colorc[0] == colorc[i]; i++) { ; }
00204         if (i == sizeof(color)) {
00205             // All "color" bytes are identical, use memset (fast)
00206             while (height--) {
00207                 memset(pp, colorc[0], this->pixelbytes * w);
00208                 pp += this->linesize;
00209             }
00210         } else {
00211             // Cannot use memset, use a variant working on shorts/ints (slow)
00212             while (height--) {
00213                 switch(this->pixelbytes) {
00214                 case 2:
00215                     memset_s(pp, color, w);
00216                     break;
00217                 case 4:
00218                     memset_l(pp, color, w);
00219                     break;
00220                 default:
00221                     error("Unsupported pixel size %i", this->pixelbytes);
00222                 }
00223                 pp += this->linesize;
00224             }
00225         }
00226     }
00227 }
00228 
00229 inline static void blitPixel(uint8 offset, unsigned int *from_z, unsigned int *to_z, unsigned int z_length, byte *from_color, byte *to_color, unsigned int color_length) {
00230     const unsigned int d = from_z[offset];
00231     if (d > to_z[offset]) {
00232         memcpy(to_color + offset, from_color + offset, color_length);
00233         memcpy(to_z + offset, &d, z_length);
00234     }
00235 }
00236 
00237 void FrameBuffer::blitOffscreenBuffer(Buffer *buf) {
00238     // TODO: could be faster, probably.
00239 #define UNROLL_COUNT 16
00240     if (buf->used) {
00241         const int pixel_bytes = this->pixelbytes;
00242         const int unrolled_pixel_bytes = pixel_bytes * UNROLL_COUNT;
00243         byte *to = this->pbuf.getRawBuffer();
00244         byte *from = buf->pbuf;
00245         unsigned int *to_z = this->_zbuf;
00246         unsigned int *from_z = buf->zbuf;
00247         int count = this->xsize * this->ysize;
00248         while (count >= UNROLL_COUNT) {
00249             blitPixel(0x0, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00250             blitPixel(0x1, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00251             blitPixel(0x2, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00252             blitPixel(0x3, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00253             blitPixel(0x4, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00254             blitPixel(0x5, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00255             blitPixel(0x6, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00256             blitPixel(0x7, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00257             blitPixel(0x8, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00258             blitPixel(0x9, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00259             blitPixel(0xA, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00260             blitPixel(0xB, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00261             blitPixel(0xC, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00262             blitPixel(0xD, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00263             blitPixel(0xE, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00264             blitPixel(0xF, from_z, to_z, sizeof(int), from, to, pixel_bytes);
00265             count -= UNROLL_COUNT;
00266             to += unrolled_pixel_bytes;
00267             from += unrolled_pixel_bytes;
00268             to_z += UNROLL_COUNT;
00269         }
00270         switch (count) {
00271         case 0xF: blitPixel(0xE, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00272         case 0xE: blitPixel(0xD, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00273         case 0xD: blitPixel(0xC, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00274         case 0xC: blitPixel(0xB, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00275         case 0xB: blitPixel(0xA, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00276         case 0xA: blitPixel(0x9, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00277         case 0x9: blitPixel(0x8, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00278         case 0x8: blitPixel(0x7, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00279         case 0x7: blitPixel(0x6, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00280         case 0x6: blitPixel(0x5, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00281         case 0x5: blitPixel(0x4, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00282         case 0x4: blitPixel(0x3, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00283         case 0x3: blitPixel(0x2, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00284         case 0x2: blitPixel(0x1, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00285         case 0x1: blitPixel(0x0, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
00286         case 0x0: break;
00287         }
00288     }
00289 #undef UNROLL_COUNT
00290 }
00291 
00292 void FrameBuffer::selectOffscreenBuffer(Buffer *buf) {
00293     if (buf) {
00294         this->pbuf = buf->pbuf;
00295         this->_zbuf = buf->zbuf;
00296         buf->used = true;
00297     } else {
00298         this->pbuf = this->buffer.pbuf;
00299         this->_zbuf = this->buffer.zbuf;
00300     }
00301 }
00302 
00303 void FrameBuffer::clearOffscreenBuffer(Buffer *buf) {
00304     memset(buf->pbuf, 0, this->ysize * this->linesize);
00305     memset(buf->zbuf, 0, this->ysize * this->xsize * sizeof(unsigned int));
00306     buf->used = false;
00307 }
00308 
00309 void FrameBuffer::setTexture(const Graphics::PixelBuffer &texture) {
00310     current_texture = texture;
00311 }
00312 
00313 } // end of namespace TinyGL


Generated on Sat Mar 23 2019 05:02:23 for ResidualVM by doxygen 1.7.1
curved edge   curved edge