Thanasis Antoniou cd076b26ae BLADERUNNER: Using preincrement and pre-decrease where possible
In case the compiler won't optimize such cases
2020-02-24 21:24:06 +02:00

227 lines
5.0 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "bladerunner/zbuffer.h"
#include "bladerunner/decompress_lzo.h"
#include "common/debug.h"
namespace BladeRunner {
void ZBufferDirtyRects::reset() {
_count = 0;
}
bool ZBufferDirtyRects::add(Common::Rect rect) {
if (_count == MAX_DIRTY_RECTS)
return false;
_rects[_count++] = rect;
if (_count > 1) {
extendExisting();
}
return true;
}
void ZBufferDirtyRects::extendExisting() {
if (_count < 2)
return;
Common::Rect last = _rects[_count - 1];
int i;
for (i = 0; i != _count - 1; ++i) {
if (last.intersects(_rects[i])) {
_rects[i].extend(last);
--_count;
break;
}
}
}
int ZBufferDirtyRects::getCount() const {
return _count;
}
bool ZBufferDirtyRects::popRect(Common::Rect *rect) {
if (_count == 0)
return false;
*rect = _rects[--_count];
return true;
}
ZBuffer::ZBuffer() {
_zbuf1 = nullptr;
_zbuf2 = nullptr;
_dirtyRects = new ZBufferDirtyRects();
_width = 0;
_height = 0;
enable();
}
ZBuffer::~ZBuffer() {
delete[] _zbuf2;
delete[] _zbuf1;
delete _dirtyRects;
}
void ZBuffer::init(int width, int height) {
_width = width;
_height = height;
_zbuf1 = new uint16[width * height];
_zbuf2 = new uint16[width * height];
}
static int decodePartialZBuffer(const uint8 *src, uint16 *curZBUF, uint32 srcLen) {
uint32 dstSize = 640 * 480; // This is taken from global variables?
uint32 dstRemain = dstSize;
uint16 *curzp = curZBUF;
const uint16 *inp = (const uint16 *)src;
while (dstRemain && (inp - (const uint16 *)src) < (std::ptrdiff_t)srcLen) {
uint32 count = FROM_LE_16(*inp++);
if (count & 0x8000) {
count = MIN(count & 0x7fff, dstRemain);
dstRemain -= count;
while (count--) {
uint16 value = FROM_LE_16(*inp++);
if (value)
*curzp = value;
++curzp;
}
} else {
count = MIN(count, dstRemain);
dstRemain -= count;
uint16 value = FROM_LE_16(*inp++);
if (!value) {
curzp += count;
} else {
while (count--)
*curzp++ = value;
}
}
}
return dstSize - dstRemain;
}
bool ZBuffer::decodeData(const uint8 *data, int size) {
if (_disabled) {
return false;
}
uint32 width, height, complete;// , unk0;
width = READ_LE_UINT32(data + 0);
height = READ_LE_UINT32(data + 4);
complete = READ_LE_UINT32(data + 8);
/*unk0 =*/ READ_LE_UINT32(data + 12);
if (width != (uint32)_width || height != (uint32)_height) {
warning("zbuffer size mismatch (%d, %d) != (%d, %d)", _width, _height, width, height);
return false;
}
data += 16;
size -= 16;
if (complete) {
resetUpdates();
size_t zbufOutSize;
decompress_lzo1x(data, size, (uint8 *)_zbuf1, &zbufOutSize);
#ifdef SCUMM_BIG_ENDIAN
// As the compression is working with 8-bit data, on big-endian architectures we have to switch order of bytes in uncompressed data
uint8 *rawZbuf = (uint8 *)_zbuf1;
for (size_t i = 0; i < zbufOutSize - 1; i += 2) {
SWAP(rawZbuf[i], rawZbuf[i + 1]);
}
#endif
memcpy(_zbuf2, _zbuf1, 2 * _width * _height);
} else {
clean();
decodePartialZBuffer(data, _zbuf1, size);
decodePartialZBuffer(data, _zbuf2, size);
}
return true;
}
uint16 *ZBuffer::getData() const {
return _zbuf2;
}
uint16 ZBuffer::getZValue(int x, int y) const {
assert(x >= 0 && x < _width);
assert(y >= 0 && y < _height);
if (_zbuf2 == nullptr) {
return 0;
}
return _zbuf2[y * _width + x];
}
void ZBuffer::blit(Common::Rect rect) {
int line_width = rect.width();
for (int y = rect.top; y != rect.bottom; ++y) {
int offset = y * _width + rect.left;
memcpy(_zbuf2 + offset, _zbuf1 + offset, 2 * line_width);
}
}
void ZBuffer::mark(Common::Rect rect) {
assert(rect.isValidRect());
// debug("mark %d, %d, %d, %d", rect.top, rect.right, rect.bottom, rect.left);
rect.clip(_width, _height);
_dirtyRects->add(rect);
}
void ZBuffer::clean() {
Common::Rect rect;
while (_dirtyRects->popRect(&rect)) {
// debug("blit %d, %d, %d, %d", rect.top, rect.right, rect.bottom, rect.left);
blit(rect);
}
}
void ZBuffer::resetUpdates() {
_dirtyRects->reset();
}
void ZBuffer::disable() {
_disabled = true;
}
void ZBuffer::enable() {
_disabled = false;
}
} // End of namespace BladeRunner