[Scummvm-git-logs] scummvm master -> 66e36e6d3bffa763fd38c8b794fd9cf898d5b1da
mduggan
mgithub at guarana.org
Thu Apr 2 11:54:18 UTC 2020
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
66e36e6d3b ULTIMA8: Uncompress shapes on load for simpler render path (#2169)
Commit: 66e36e6d3bffa763fd38c8b794fd9cf898d5b1da
https://github.com/scummvm/scummvm/commit/66e36e6d3bffa763fd38c8b794fd9cf898d5b1da
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-04-02T20:54:14+09:00
Commit Message:
ULTIMA8: Uncompress shapes on load for simpler render path (#2169)
Changed paths:
A engines/ultima/ultima8/graphics/raw_shape_frame.cpp
A engines/ultima/ultima8/graphics/raw_shape_frame.h
engines/ultima/module.mk
engines/ultima/ultima8/graphics/shape.cpp
engines/ultima/ultima8/graphics/shape.h
engines/ultima/ultima8/graphics/shape_frame.cpp
engines/ultima/ultima8/graphics/shape_frame.h
engines/ultima/ultima8/graphics/soft_render_surface.inl
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 979b72db9d..c8a552adc8 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -369,6 +369,7 @@ MODULE_OBJS := \
ultima8/graphics/palette_fader_process.o \
ultima8/graphics/palette_manager.o \
ultima8/graphics/point_scaler.o \
+ ultima8/graphics/raw_shape_frame.o \
ultima8/graphics/render_surface.o \
ultima8/graphics/shape.o \
ultima8/graphics/shape_archive.o \
diff --git a/engines/ultima/ultima8/graphics/raw_shape_frame.cpp b/engines/ultima/ultima8/graphics/raw_shape_frame.cpp
new file mode 100644
index 0000000000..f9fceb02a4
--- /dev/null
+++ b/engines/ultima/ultima8/graphics/raw_shape_frame.cpp
@@ -0,0 +1,164 @@
+/* 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 "ultima/ultima8/misc/pent_include.h"
+
+#include "ultima/ultima8/graphics/raw_shape_frame.h"
+#include "ultima/ultima8/convert/convert_shape.h"
+#include "ultima/ultima8/convert/u8/convert_shape_u8.h"
+#include "ultima/ultima8/filesys/idata_source.h"
+
+#include "common/memstream.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+/*
+ parse data and fill class
+ */
+RawShapeFrame::RawShapeFrame(const uint8 *data, uint32 size, const ConvertShapeFormat *format,
+ const uint8 special[256], ConvertShapeFrame *prev) : _line_offsets(0) {
+ // Load it as u8
+ if (!format || format == &U8ShapeFormat || format == &U82DShapeFormat)
+ loadU8Format(data, size);
+ else if (format == &PentagramShapeFormat)
+ loadPentagramFormat(data, size);
+ else if (format == &U8CMPShapeFormat)
+ loadU8CMPFormat(data, size, format, special, prev);
+ else
+ loadGenericFormat(data, size, format);
+}
+
+RawShapeFrame::~RawShapeFrame() {
+ delete [] _line_offsets;
+}
+
+// This will load a u8 style shape 'optimized'.
+void RawShapeFrame::loadU8Format(const uint8 *data, uint32 size) {
+ Common::MemoryReadStream stream(data, size + 8);
+
+ stream.skip(8); // skip header
+ _compressed = stream.readByte();
+ stream.skip(1);
+ _width = stream.readUint16LE();
+ _height = stream.readUint16LE();
+ _xoff = stream.readUint16LE();
+ _yoff = stream.readUint16LE();
+
+ if (_height == 0)
+ return;
+
+ _line_offsets = new uint32[_height];
+
+ for (int32 i = 0; i < _height; i++) {
+ _line_offsets[i] = stream.readUint16LE() - ((_height - i) * 2);
+ }
+
+ _rle_data = data + stream.pos();
+}
+
+// This will load a pentagram style shape 'optimized'.
+void RawShapeFrame::loadPentagramFormat(const uint8 *data, uint32 size) {
+ Common::MemoryReadStream stream(data, size);
+
+ _compressed = stream.readByte();
+ stream.skip(3);
+ _width = stream.readSint32LE();
+ _height = stream.readSint32LE();
+ _xoff = stream.readSint32LE();
+ _yoff = stream.readSint32LE();
+
+ if (_height == 0)
+ return;
+
+ _line_offsets = new uint32[_height];
+
+ for (int32 i = 0; i < _height; i++) {
+ _line_offsets[i] = stream.readSint32LE();
+ }
+
+ _rle_data = data + stream.pos();
+}
+
+// This will load any sort of shape via a ConvertShapeFormat struct
+void RawShapeFrame::loadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
+ IBufferDataSource ds(data + format->_bytes_frame_unknown, size);
+
+ _compressed = ds.readX(format->_bytes_frame_compression);
+ _width = ds.readXS(format->_bytes_frame_width);
+ _height = ds.readXS(format->_bytes_frame_height);
+ _xoff = ds.readXS(format->_bytes_frame_xoff);
+ _yoff = ds.readXS(format->_bytes_frame_yoff);
+
+ if (_height == 0)
+ return;
+
+ _line_offsets = new uint32[_height];
+
+ for (int32 i = 0; i < _height; i++) {
+ if (format->_line_offset_absolute) {
+ _line_offsets[i] = ds.readX(format->_bytes_line_offset);
+ } else {
+ _line_offsets[i] = ds.readX(format->_bytes_line_offset) - ((_height - i) * format->_bytes_line_offset);
+ }
+ }
+
+ _rle_data = data + format->_len_frameheader2 + _height * format->_bytes_line_offset;
+}
+
+// This will load an U8-compressed shape
+void RawShapeFrame::loadU8CMPFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format, const uint8 special[256], ConvertShapeFrame *prev) {
+ IBufferDataSource ds(data, size);
+
+ ConvertShapeFrame f;
+
+ f.ReadCmpFrame(&ds, format, special, prev);
+
+ uint32 to_alloc = f._height + (f._bytes_rle + 3) / 4;
+ _line_offsets = new uint32[to_alloc];
+ _rle_data = reinterpret_cast<uint8 *>(_line_offsets + f._height);
+
+ _compressed = f._compression;
+ _height = f._height;
+ _width = f._width;
+ _xoff = f._xoff;
+ _yoff = f._yoff;
+
+ memcpy(_line_offsets, f._line_offsets, f._height * 4);
+ memcpy(const_cast<uint8 *>(_rle_data), f._rle_data, f._bytes_rle);
+
+ f.Free();
+}
+
+void RawShapeFrame::getConvertShapeFrame(ConvertShapeFrame &csf) {
+ csf._compression = _compressed;
+ csf._width = _width;
+ csf._height = _height;
+ csf._xoff = _xoff;
+ csf._yoff = _yoff;
+ csf._line_offsets = _line_offsets;
+ csf._bytes_rle = 0;
+ csf._rle_data = const_cast<uint8 *>(_rle_data);
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/graphics/raw_shape_frame.h b/engines/ultima/ultima8/graphics/raw_shape_frame.h
new file mode 100644
index 0000000000..13f0660908
--- /dev/null
+++ b/engines/ultima/ultima8/graphics/raw_shape_frame.h
@@ -0,0 +1,79 @@
+/* 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.
+ *
+ */
+
+#ifndef ULTIMA8_GRAPHICS_RAW_SHAPEFRAME_H
+#define ULTIMA8_GRAPHICS_RAW_SHAPEFRAME_H
+
+namespace Ultima {
+namespace Ultima8 {
+
+struct ConvertShapeFormat;
+struct ConvertShapeFrame;
+
+/**
+ * A raw shape frame just contains references into the (possibly compressed)
+ * data for the shape and is used as an intermediate step in the loading
+ * process.
+ */
+class RawShapeFrame {
+ friend class ShapeFrame;
+public:
+
+ // parse data.
+ //
+ // You will find this is quite similar to the ConvertShapeFrame except
+ // all the unknown crap is removed. It's designed to allow for painting
+ // only, and for speed when loading.
+
+ RawShapeFrame(const uint8 *data, uint32 size, const ConvertShapeFormat *format = 0,
+ const uint8 special[256] = 0, ConvertShapeFrame *prev = 0);
+ ~RawShapeFrame();
+
+ void getConvertShapeFrame(ConvertShapeFrame &csf);
+
+private:
+
+ uint32 _compressed;
+ int32 _width, _height;
+ int32 _xoff, _yoff;
+
+ uint32 *_line_offsets; // Note these are offsets into rle_data
+ const uint8 *_rle_data;
+
+ // This will load a u8 style shape 'optimized'.
+ void loadU8Format(const uint8 *data, uint32 size);
+
+ // This will load a pentagram style shape 'optimized'.
+ void loadPentagramFormat(const uint8 *data, uint32 size);
+
+ // This will load any sort of shape via a ConvertShapeFormat struct
+ // Crusader shapes must be loaded this way
+ void loadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
+
+ // This will load a u8-compressed shape
+ void loadU8CMPFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format, const uint8 special[256], ConvertShapeFrame *prev);
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/graphics/shape.cpp b/engines/ultima/ultima8/graphics/shape.cpp
index dba08732a3..29fe8ee275 100644
--- a/engines/ultima/ultima8/graphics/shape.cpp
+++ b/engines/ultima/ultima8/graphics/shape.cpp
@@ -24,11 +24,14 @@
#include "ultima/ultima8/graphics/shape.h"
#include "ultima/ultima8/graphics/shape_frame.h"
+#include "ultima/ultima8/graphics/raw_shape_frame.h"
#include "ultima/ultima8/convert/convert_shape.h"
#include "ultima/ultima8/convert/u8/convert_shape_u8.h"
#include "ultima/ultima8/convert/crusader/convert_shape_crusader.h"
#include "ultima/ultima8/filesys/idata_source.h"
+#include "common/memstream.h"
+
namespace Ultima {
namespace Ultima8 {
@@ -36,42 +39,35 @@ DEFINE_RUNTIME_CLASSTYPE_CODE_BASE_CLASS(Shape)
DEFINE_CUSTOM_MEMORY_ALLOCATION(Shape)
-Shape::Shape(const uint8 *data_, uint32 size_, const ConvertShapeFormat *format,
- const uint16 id, const uint32 shape) : _flexId(id), _shapeNum(shape) {
+Shape::Shape(const uint8 *data, uint32 size, const ConvertShapeFormat *format,
+ const uint16 id, const uint32 shape)
+ : _flexId(id), _shapeNum(shape), _palette(nullptr) {
// NB: U8 style!
+ loadFrames(data, size, format);
- this->_data = data_;
- this->_size = size_;
- this->_palette = nullptr;
-
- if (!format) format = DetectShapeFormat(data_, size_);
-
- if (!format) {
- // Should be fatal?
- perr << "Error: Unable to detect shape format" << Std::endl;
- return;
- }
-
- // Load it as u8
- if (format == &U8ShapeFormat || format == &U82DShapeFormat)
- LoadU8Format(data_, size_, format);
- else if (format == &PentagramShapeFormat)
- LoadPentagramFormat(data_, size_, format);
- else
- LoadGenericFormat(data_, size_, format);
+ delete[] const_cast<uint8 *>(data);
}
Shape::Shape(IDataSource *src, const ConvertShapeFormat *format)
: _flexId(0), _shapeNum(0), _palette(nullptr) {
// NB: U8 style!
+ uint32 size = src->getSize();
+ uint8 *data = new uint8[size];
+ src->read(data, size);
+
+ loadFrames(data, size, format);
- this->_size = src->getSize();
- uint8 *d = new uint8[this->_size];
- this->_data = d;
- src->read(d, this->_size);
+ delete[] data;
+}
+Shape::~Shape() {
+ for (uint i = 0; i < _frames.size(); ++i)
+ delete _frames[i];
+}
+
+void Shape::loadFrames(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
if (!format)
- format = DetectShapeFormat(_data, _size);
+ format = DetectShapeFormat(data, size);
if (!format) {
// Should be fatal?
@@ -79,20 +75,20 @@ Shape::Shape(IDataSource *src, const ConvertShapeFormat *format)
return;
}
+ Common::Array<RawShapeFrame *> rawframes;
// Load it as u8
+
if (format == &U8ShapeFormat || format == &U82DShapeFormat)
- LoadU8Format(_data, _size, format);
+ rawframes = loadU8Format(data, size, format);
else if (format == &PentagramShapeFormat)
- LoadPentagramFormat(_data, _size, format);
+ rawframes = loadPentagramFormat(data, size, format);
else
- LoadGenericFormat(_data, _size, format);
-}
-
-Shape::~Shape() {
- for (unsigned int i = 0; i < _frames.size(); ++i)
- delete _frames[i];
+ rawframes = loadGenericFormat(data, size, format);
- delete[] const_cast<uint8 *>(_data);
+ for (uint i = 0; i < rawframes.size(); i++) {
+ _frames.push_back(new ShapeFrame(rawframes[i]));
+ delete rawframes[i];
+ }
}
void Shape::getShapeId(uint16 &id, uint32 &shape) const {
@@ -100,57 +96,64 @@ void Shape::getShapeId(uint16 &id, uint32 &shape) const {
shape = _shapeNum;
}
-// Some macros to make things easier
-#define READ1(data,offset) (data[offset])
-#define READ2(data,offset) (data[offset] + (data[offset+1] << 8))
-#define READ3(data,offset) (data[offset] + (data[offset+1] << 8) + (data[offset+2] << 16))
-#define READ4(data,offset) (data[offset] + (data[offset+1] << 8) + (data[offset+2] << 16) + (data[offset+3] << 24))
+// This will load a u8 style shape 'optimized'.
+Common::Array<RawShapeFrame *> Shape::loadU8Format(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
+ Common::MemoryReadStream stream(data, size);
+ stream.skip(4); // skip header
+ unsigned int framecount = stream.readUint16LE();
-// This will load a u8 style shape 'optimzed'.
-void Shape::LoadU8Format(const uint8 *data_, uint32 size_, const ConvertShapeFormat *format) {
- unsigned int framecount = READ2(data_, 4);
+ Common::Array<RawShapeFrame *> frames;
if (framecount == 0) {
- LoadGenericFormat(data_, size_, format);
- return;
+ loadGenericFormat(data, size, format);
+ return frames;
}
- _frames.reserve(framecount);
+ frames.reserve(framecount);
- for (unsigned int i = 0; i < framecount; ++i) {
- uint32 frameoffset = READ3(data_, 6 + 6 * i);
- uint32 framesize = READ2(data_, 10 + 6 * i);
+ for (uint i = 0; i < framecount; ++i) {
+ uint32 frameoffset = stream.readUint32LE() & 0xFFFFFF;
+ uint32 framesize = stream.readUint16LE();
- _frames.push_back(new ShapeFrame(data_ + frameoffset, framesize, format));
+ frames.push_back(new RawShapeFrame(data + frameoffset, framesize, format));
}
+
+ return frames;
}
-// This will load a pentagram style shape 'optimzed'.
-void Shape::LoadPentagramFormat(const uint8 *data_, uint32 size_, const ConvertShapeFormat *format) {
- unsigned int framecount = READ4(data_, 4);
+// This will load a pentagram style shape 'optimized'.
+Common::Array<RawShapeFrame *> Shape::loadPentagramFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
+ Common::MemoryReadStream stream(data, size);
+ stream.skip(4); // skip header
+ unsigned int framecount = stream.readUint16LE();
+ Common::Array<RawShapeFrame *> frames;
if (framecount == 0) {
- LoadGenericFormat(data_, size_, format);
- return;
+ loadGenericFormat(data, size, format);
+ return frames;
}
- _frames.reserve(framecount);
+ frames.reserve(framecount);
- for (unsigned int i = 0; i < framecount; ++i) {
- uint32 frameoffset = READ4(data_, 8 + 8 * i);
- uint32 framesize = READ4(data_, 12 + 8 * i);
+ for (uint i = 0; i < framecount; ++i) {
+ uint32 frameoffset = stream.readUint32LE();
+ uint32 framesize = stream.readUint32LE();
- _frames.push_back(new ShapeFrame(data_ + frameoffset, framesize, format));
+ frames.push_back(new RawShapeFrame(data + frameoffset, framesize, format));
}
+
+ return frames;
}
// This will load any sort of shape via a ConvertShapeFormat struct
-void Shape::LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
+Common::Array<RawShapeFrame *> Shape::loadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
uint32 framecount;
uint32 frameoffset;
uint32 framesize;
IBufferDataSource ds(data, size);
+ Common::Array<RawShapeFrame *> frames;
+
if (format->_bytes_ident) {
uint8 *ident = new uint8[format->_bytes_ident];
ds.read(ident, format->_bytes_ident);
@@ -158,8 +161,8 @@ void Shape::LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShape
delete[] ident;
if (!match) {
- _frames.clear();
- return;
+ frames.clear();
+ return frames;
}
}
@@ -178,9 +181,9 @@ void Shape::LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShape
else framecount = 1;
if (framecount == 0) framecount = ConvertShape::CalcNumFrames(&ds, format, size, 0);
- _frames.reserve(framecount);
+ frames.reserve(framecount);
- for (unsigned int i = 0; i < framecount; ++i) {
+ for (uint i = 0; i < framecount; ++i) {
// Read the offset
if (format->_bytes_frame_offset) frameoffset = ds.readX(format->_bytes_frame_offset) + format->_bytes_special;
else frameoffset = format->_len_header + (format->_len_frameheader * i);
@@ -196,11 +199,13 @@ void Shape::LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShape
if (format->_bytes_special && i > 0) {
prev = &p;
- _frames[i - 1]->getConvertShapeFrame(p);
+ frames[i - 1]->getConvertShapeFrame(p);
}
- _frames.push_back(new ShapeFrame(data + frameoffset, framesize, format, special, prev));
+ frames.push_back(new RawShapeFrame(data + frameoffset, framesize, format, special, prev));
}
+
+ return frames;
}
// This will detect the format of a shape
@@ -242,7 +247,7 @@ void Shape::getTotalDimensions(int32 &w, int32 &h, int32 &x, int32 &y) const {
int32 minx = 1000000, maxx = -1000000;
int32 miny = 1000000, maxy = -1000000;
- for (unsigned int i = 0; i < _frames.size(); ++i) {
+ for (uint i = 0; i < _frames.size(); ++i) {
ShapeFrame *frame = _frames[i];
if (-frame->_xoff < minx)
minx = -frame->_xoff;
diff --git a/engines/ultima/ultima8/graphics/shape.h b/engines/ultima/ultima8/graphics/shape.h
index 40a331b330..7b99d6c666 100644
--- a/engines/ultima/ultima8/graphics/shape.h
+++ b/engines/ultima/ultima8/graphics/shape.h
@@ -30,6 +30,7 @@ namespace Ultima {
namespace Ultima8 {
class ShapeFrame;
+class RawShapeFrame;
struct Palette;
struct Rect;
struct ConvertShapeFormat;
@@ -73,23 +74,22 @@ public:
ENABLE_CUSTOM_MEMORY_ALLOCATION()
private:
+ void loadFrames(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
// This will load a u8 style shape 'optimized'.
- void LoadU8Format(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
+ static Common::Array<RawShapeFrame *> loadU8Format(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
// This will load a pentagram style shape 'optimized'.
- void LoadPentagramFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
+ static Common::Array<RawShapeFrame *> loadPentagramFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
// This will load any sort of shape via a ConvertShapeFormat struct
// Crusader shapes must be loaded this way
- void LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
+ static Common::Array<RawShapeFrame *> loadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
- Std::vector<ShapeFrame *> _frames;
+ Common::Array<ShapeFrame *> _frames;
const Palette *_palette;
- const uint8 *_data;
- uint32 _size;
const uint16 _flexId;
const uint32 _shapeNum;
};
diff --git a/engines/ultima/ultima8/graphics/shape_frame.cpp b/engines/ultima/ultima8/graphics/shape_frame.cpp
index e314927195..f52ef9548c 100644
--- a/engines/ultima/ultima8/graphics/shape_frame.cpp
+++ b/engines/ultima/ultima8/graphics/shape_frame.cpp
@@ -23,128 +23,60 @@
#include "ultima/ultima8/misc/pent_include.h"
#include "ultima/ultima8/graphics/shape_frame.h"
-#include "ultima/ultima8/convert/convert_shape.h"
-#include "ultima/ultima8/convert/u8/convert_shape_u8.h"
-#include "ultima/ultima8/filesys/idata_source.h"
+#include "ultima/ultima8/graphics/raw_shape_frame.h"
namespace Ultima {
namespace Ultima8 {
-/*
- parse data and fill class
- */
-ShapeFrame::ShapeFrame(const uint8 *data, uint32 size, const ConvertShapeFormat *format,
- const uint8 special[256], ConvertShapeFrame *prev) : _line_offsets(0) {
- // Load it as u8
- if (!format || format == &U8ShapeFormat || format == &U82DShapeFormat)
- LoadU8Format(data, size);
- else if (format == &PentagramShapeFormat)
- LoadPentagramFormat(data, size);
- else if (format == &U8CMPShapeFormat)
- LoadU8CMPFormat(data, size, format, special, prev);
- else
- LoadGenericFormat(data, size, format);
-}
+ShapeFrame::ShapeFrame(const RawShapeFrame *rawframe) :
+ _xoff(rawframe->_xoff), _yoff(rawframe->_yoff),
+ _width(rawframe->_width), _height(rawframe->_height) {
-ShapeFrame::~ShapeFrame() {
- delete [] _line_offsets;
-}
+ _pixels = new uint8[_width * _height];
+ _mask = new uint8[_width * _height];
-// Some macros to make things easier
-#define READ1(data,offset) (data[offset])
-#define READ2(data,offset) (data[offset] + (data[offset+1] << 8))
-#define READ4(data,offset) (data[offset] + (data[offset+1] << 8) + (data[offset+2] << 16) + (data[offset+3] << 24))
+ memset(_mask, 0, _width * _height);
-// This will load a u8 style shape 'optimzed'.
-void ShapeFrame::LoadU8Format(const uint8 *data, uint32 /*size*/) {
- _compressed = READ1(data, 8);
- _width = static_cast<int16>(READ2(data, 10));
- _height = static_cast<int16>(READ2(data, 12));
- _xoff = static_cast<int16>(READ2(data, 14));
- _yoff = static_cast<int16>(READ2(data, 16));
+ for (int y = 0; y < _height; y++) {
+ int32 xpos = 0;
+ const uint8 *linedata = rawframe->_rle_data + rawframe->_line_offsets[y];
- if (_height == 0)
- return;
+ do {
+ xpos += *linedata++;
- _line_offsets = new uint32[_height];
+ if (xpos >= _width)
+ break;
- data += 18;
- for (int32 i = 0; i < _height; i++) {
- _line_offsets[i] = READ2(data, 0) - ((_height - i) * 2);
- data += 2;
- }
+ int32 dlen = *linedata++;
+ int type = 0;
- _rle_data = data;
-}
+ if (rawframe->_compressed) {
+ type = dlen & 1;
+ dlen >>= 1;
+ }
-// This will load a pentagram style shape 'optimzed'.
-void ShapeFrame::LoadPentagramFormat(const uint8 *data, uint32 /*size*/) {
- _compressed = READ1(data, 0);
- _width = static_cast<int32>(READ4(data, 4));
- _height = static_cast<int32>(READ4(data, 8));
- _xoff = static_cast<int32>(READ4(data, 12));
- _yoff = static_cast<int32>(READ4(data, 16));
+ for (int doff = 0; doff < dlen; doff++) {
+ _pixels[y * _width + xpos + doff] = *linedata;
+ _mask[y * _width + xpos + doff] = 1;
+ if (!type) {
+ linedata++;
+ }
+ }
- if (_height == 0) return;
+ xpos += dlen;
+ if (type) {
+ linedata++;
+ }
- _line_offsets = new uint32[_height];
+ } while (xpos < _width);
- data += 20;
- for (int32 i = 0; i < _height; i++) {
- _line_offsets[i] = READ4(data, 0);
- data += 4;
}
- _rle_data = data;
-}
-
-// This will load any sort of shape via a ConvertShapeFormat struct
-void ShapeFrame::LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format) {
- IBufferDataSource ds(data, size);
-
- ds.skip(format->_bytes_frame_unknown);
- _compressed = ds.readX(format->_bytes_frame_compression);
- _width = ds.readXS(format->_bytes_frame_width);
- _height = ds.readXS(format->_bytes_frame_height);
- _xoff = ds.readXS(format->_bytes_frame_xoff);
- _yoff = ds.readXS(format->_bytes_frame_yoff);
-
- if (_height == 0) return;
-
- _line_offsets = new uint32[_height];
-
- if (format->_line_offset_absolute) for (int32 i = 0; i < _height; i++) {
- _line_offsets[i] = ds.readX(format->_bytes_line_offset);
- }
- else for (int32 i = 0; i < _height; i++) {
- _line_offsets[i] = ds.readX(format->_bytes_line_offset) - ((_height - i) * format->_bytes_line_offset);
- }
-
- _rle_data = data + format->_len_frameheader2 + _height * format->_bytes_line_offset;
}
-// This will load an U8-compressed shape
-void ShapeFrame::LoadU8CMPFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format, const uint8 special[256], ConvertShapeFrame *prev) {
- IBufferDataSource ds(data, size);
-
- ConvertShapeFrame f;
-
- f.ReadCmpFrame(&ds, format, special, prev);
-
- uint32 to_alloc = f._height + (f._bytes_rle + 3) / 4;
- _line_offsets = new uint32[to_alloc];
- _rle_data = reinterpret_cast<uint8 *>(_line_offsets + f._height);
-
- _compressed = f._compression;
- _height = f._height;
- _width = f._width;
- _xoff = f._xoff;
- _yoff = f._yoff;
-
- Std::memcpy(_line_offsets, f._line_offsets, f._height * 4);
- Std::memcpy(const_cast<uint8 *>(_rle_data), f._rle_data, f._bytes_rle);
-
- f.Free();
+ShapeFrame::~ShapeFrame() {
+ delete [] _pixels;
+ delete [] _mask;
}
// Checks to see if the frame has a pixel at the point
@@ -154,39 +86,10 @@ bool ShapeFrame::hasPoint(int32 x, int32 y) const {
y += _yoff;
// First gross culling based on dims
- if (x < 0 || y < 0 || x >= _width || y >= _height) return false;
-
- //
- // This is all pretty simple.
- //
- // All we do is decompress the line the check is on. Then we see if there
- // is a pixel at the location.
- //
-
- int32 xpos = 0;
- const uint8 *linedata = _rle_data + _line_offsets[y];
-
- do {
- xpos += *linedata++;
-
- if (xpos == _width) break;
-
- int32 dlen = *linedata++;
- int type = 0;
-
- if (_compressed) {
- type = dlen & 1;
- dlen >>= 1;
- }
-
- if (x >= xpos && x < (xpos + dlen)) return true;
- xpos += dlen;
- if (!type) linedata += dlen;
- else linedata++;
-
- } while (xpos < _width);
+ if (x < 0 || y < 0 || x >= _width || y >= _height)
+ return false;
- return false;
+ return _mask[y * _width + x] != 0;
}
// Get the pixel at the point
@@ -199,52 +102,7 @@ uint8 ShapeFrame::getPixelAtPoint(int32 x, int32 y) const {
if (x < 0 || y < 0 || x >= _width || y >= _height)
return 0xFF;
- //
- // This is all pretty simple.
- //
- // All we do is decompress the line the check is on. Then we see if there
- // is a pixel at the location. And if there is, return it
- //
-
- int32 xpos = 0;
- const uint8 *linedata = _rle_data + _line_offsets[y];
-
- do {
- xpos += *linedata++;
-
- if (xpos == _width)
- break;
-
- int32 dlen = *linedata++;
- int type = 0;
-
- if (_compressed) {
- type = dlen & 1;
- dlen >>= 1;
- }
-
- if (x >= xpos && x < (xpos + dlen)) {
- if (!type) linedata += x - xpos;
- return *linedata;
- }
- xpos += dlen;
- if (!type) linedata += dlen;
- else linedata++;
-
- } while (xpos < _width);
-
- return 0xFF;
-}
-
-void ShapeFrame::getConvertShapeFrame(ConvertShapeFrame &csf) {
- csf._compression = _compressed;
- csf._width = _width;
- csf._height = _height;
- csf._xoff = _xoff;
- csf._yoff = _yoff;
- csf._line_offsets = _line_offsets;
- csf._bytes_rle = 0;
- csf._rle_data = const_cast<uint8 *>(_rle_data);
+ return _pixels[y * _width + x];
}
} // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/graphics/shape_frame.h b/engines/ultima/ultima8/graphics/shape_frame.h
index afbe59c52c..e7ca1262b7 100644
--- a/engines/ultima/ultima8/graphics/shape_frame.h
+++ b/engines/ultima/ultima8/graphics/shape_frame.h
@@ -26,48 +26,24 @@
namespace Ultima {
namespace Ultima8 {
-struct ConvertShapeFormat;
-struct ConvertShapeFrame;
+class RawShapeFrame;
+/** A decompressed version of the RawShapeFrame for easier rendering */
class ShapeFrame {
public:
- // parse data.
- //
- // You will find this is quite similar to the ConvertShapeFrame except
- // all the unknown crap is removed. It's designed to allow for painting
- // only, and for speed when loading.
-
- ShapeFrame(const uint8 *data, uint32 size, const ConvertShapeFormat *format = 0,
- const uint8 special[256] = 0, ConvertShapeFrame *prev = 0);
+ ShapeFrame(const RawShapeFrame *rawframe);
~ShapeFrame();
- uint32 _compressed;
- int32 _width, _height;
- int32 _xoff, _yoff;
+ int32 _width, _height;
+ int32 _xoff, _yoff;
- uint32 *_line_offsets; // Note these are offsets into rle_data
- const uint8 *_rle_data;
+ uint8 *_pixels;
+ uint8 *_mask;
bool hasPoint(int32 x, int32 y) const; // Check to see if a point is in the frame
uint8 getPixelAtPoint(int32 x, int32 y) const; // Get the pixel at the point
-
- void getConvertShapeFrame(ConvertShapeFrame &csf);
-private:
-
- // This will load a u8 style shape 'optimized'.
- void LoadU8Format(const uint8 *data, uint32 size);
-
- // This will load a pentagram style shape 'optimized'.
- void LoadPentagramFormat(const uint8 *data, uint32 size);
-
- // This will load any sort of shape via a ConvertShapeFormat struct
- // Crusader shapes must be loaded this way
- void LoadGenericFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format);
-
- // This will load a u8-compressed shape
- void LoadU8CMPFormat(const uint8 *data, uint32 size, const ConvertShapeFormat *format, const uint8 special[256], ConvertShapeFrame *prev);
};
} // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/graphics/soft_render_surface.inl b/engines/ultima/ultima8/graphics/soft_render_surface.inl
index 48c91c86db..b3734bd8ba 100644
--- a/engines/ultima/ultima8/graphics/soft_render_surface.inl
+++ b/engines/ultima/ultima8/graphics/soft_render_surface.inl
@@ -67,9 +67,9 @@
#ifdef XFORM_SHAPES
#ifdef XFORM_CONDITIONAL
-#define USE_XFORM_FUNC ((XFORM_CONDITIONAL) && xform_pal[*linedata])
+#define USE_XFORM_FUNC ((XFORM_CONDITIONAL) && xform_pal[*srcpix])
#else
-#define USE_XFORM_FUNC (xform_pal[*linedata])
+#define USE_XFORM_FUNC (xform_pal[*srcpix])
#endif
//
@@ -103,7 +103,7 @@ const int32 neg = (FLIP_CONDITIONAL)?-1:0;
//
#ifdef NO_CLIPPING
-#define LINE_END_ASSIGN()
+#define LINE_END_ASSIGN (0)
#define NOT_CLIPPED_X (1)
#define NOT_CLIPPED_Y (1)
#define OFFSET_PIXELS (_pixels)
@@ -113,14 +113,12 @@ const int32 neg = (FLIP_CONDITIONAL)?-1:0;
//
#else
-#define LINE_END_ASSIGN() do { line_end = line_start+scrn_width; } while (0)
-#define NOT_CLIPPED_Y (line >= 0 && line < scrn_height)
-#define NOT_CLIPPED_X (pixptr >= line_start && pixptr < line_end)
-
- int scrn_width = _clipWindow.w;
- int scrn_height = _clipWindow.h;
- uintX *line_end;
+ const int scrn_width = _clipWindow.w;
+ const int scrn_height = _clipWindow.h;
+#define LINE_END_ASSIGN const uintX *dst_line_end = dst_line_start + scrn_width
+#define NOT_CLIPPED_X (dstpix >= dst_line_start && dstpix < dst_line_end)
+#define NOT_CLIPPED_Y (line >= 0 && line < scrn_height)
#define OFFSET_PIXELS (off_pixels)
uint8 *off_pixels = static_cast<uint8*>(_pixels) + static_cast<sintptr>(_clipWindow.x)*sizeof(uintX) + static_cast<sintptr>(_clipWindow.y)*_pitch;
@@ -136,9 +134,9 @@ const int32 neg = (FLIP_CONDITIONAL)?-1:0;
#ifdef BLEND_SHAPES
#ifdef BLEND_CONDITIONAL
-#define CUSTOM_BLEND(src) static_cast<uintX>((BLEND_CONDITIONAL)?BLEND_SHAPES(src,*pixptr):src)
+#define CUSTOM_BLEND(src) static_cast<uintX>((BLEND_CONDITIONAL)?BLEND_SHAPES(src,*dstpix):src)
#else
-#define CUSTOM_BLEND(src) static_cast<uintX>(BLEND_SHAPES(src,*pixptr))
+#define CUSTOM_BLEND(src) static_cast<uintX>(BLEND_SHAPES(src,*dstpix))
#endif
//
@@ -174,13 +172,12 @@ const int32 neg = (FLIP_CONDITIONAL)?-1:0;
return;
const ShapeFrame *frame = s->getFrame(framenum);
- const uint8 *rle_data = frame->_rle_data;
- const uint32 *line_offsets = frame->_line_offsets;
+ const uint8 *srcpixels = frame->_pixels;
+ const uint8 *srcmask = frame->_mask;
const uint32 *pal = untformed_pal?
&(s->getPalette()->_native_untransformed[0]):
&(s->getPalette()->_native[0]);
-
#ifdef XFORM_SHAPES
const uint32 *xform_pal = untformed_pal?
&(s->getPalette()->_xform_untransformed[0]):
@@ -192,113 +189,34 @@ const int32 neg = (FLIP_CONDITIONAL)?-1:0;
x -= XNEG(frame->_xoff);
y -= frame->_yoff;
- // Do it this way if compressed
- if (frame->_compressed) for (int i=0; i<height_; i++) {
- int32 xpos = 0;
- sintptr line = y+i;
+ for (int i = 0; i < height_; i++) {
+ sintptr line = y + i;
if (NOT_CLIPPED_Y) {
- const uint8 *linedata = rle_data + line_offsets[i];
- uintX *line_start = reinterpret_cast<uintX *>(static_cast<uint8*>(OFFSET_PIXELS) + _pitch*line);
- LINE_END_ASSIGN();
-
- do {
- xpos += *linedata++;
-
- if (xpos == width_) break;
-
- int32 dlen = *linedata++;
- const int type = dlen & 1;
- dlen >>= 1;
-
- uintX *pixptr = line_start+x+XNEG(xpos);
- uintX *endrun = pixptr + XNEG(dlen);
-
- if (!type) {
- // Identical to the uncompressed case
- while (pixptr != endrun) {
- if (NOT_CLIPPED_X && NOT_DESTINATION_MASKED) {
- #ifdef XFORM_SHAPES
- if (USE_XFORM_FUNC) {
- *pixptr = CUSTOM_BLEND(BlendPreModulated(xform_pal[*linedata],*pixptr));
- } else
- #endif
- {
- *pixptr = CUSTOM_BLEND(pal[*linedata]);
- }
- }
- pixptr += XNEG(1);
- linedata++;
- }
- } else {
- // a run of the same pixel
+ const uint8 *srcline = srcpixels + i * width_;
+ const uint8 *srcmaskline = srcmask + i * width_;
+ uintX *dst_line_start = reinterpret_cast<uintX *>(static_cast<uint8*>(OFFSET_PIXELS) + _pitch * line);
+ LINE_END_ASSIGN;
+
+ for (int xpos = 0; xpos < width_; xpos++) {
+ if (srcmaskline[xpos] == 0)
+ continue;
+
+ uintX *dstpix = dst_line_start + x + XNEG(xpos);
+
+ if (NOT_CLIPPED_X && NOT_DESTINATION_MASKED) {
+ const uint8 *srcpix = srcline + xpos;
#ifdef XFORM_SHAPES
if (USE_XFORM_FUNC) {
- const uint32 pix = xform_pal[*linedata];
- while (pixptr != endrun) {
- if (NOT_CLIPPED_X && NOT_DESTINATION_MASKED) *pixptr = CUSTOM_BLEND(BlendPreModulated(pix,*pixptr));
- pixptr += XNEG(1);
- }
- } else
+ *dstpix = CUSTOM_BLEND(BlendPreModulated(xform_pal[*srcpix], *dstpix));
+ }
+ else
#endif
{
- const uint32 pix = pal[*linedata];
- while (pixptr != endrun)
- {
- if (NOT_CLIPPED_X && NOT_DESTINATION_MASKED)
- {
- *pixptr = CUSTOM_BLEND(pix);
- }
- pixptr += XNEG(1);
- }
- }
- linedata++;
- }
-
- xpos += dlen;
-
- } while (xpos < width_);
- }
- }
- // Uncompressed
- else for (int i=0; i<height_; i++) {
- int32 xpos = 0;
- sintptr line = y+i;
-
- if (NOT_CLIPPED_Y) {
- const uint8 *linedata = rle_data + line_offsets[i];
- uintX *line_start = reinterpret_cast<uintX *>(static_cast<uint8*>(OFFSET_PIXELS) + _pitch*line);
- LINE_END_ASSIGN();
-
- do {
- xpos += *linedata++;
-
- if (xpos == width_) break;
-
- const int32 dlen = *linedata++;
-
- uintX *pixptr = line_start+x+XNEG(xpos);
- uintX *endrun = pixptr + XNEG(dlen);
-
- while (pixptr != endrun) {
- if (NOT_CLIPPED_X && NOT_DESTINATION_MASKED) {
- #ifdef XFORM_SHAPES
- if (USE_XFORM_FUNC) {
- *pixptr = CUSTOM_BLEND(BlendPreModulated(xform_pal[*linedata],*pixptr));
- }
- else
- #endif
- {
- *pixptr = CUSTOM_BLEND(pal[*linedata]);
- }
+ *dstpix = CUSTOM_BLEND(pal[*srcpix]);
}
- pixptr += XNEG(1);
- linedata++;
}
-
- xpos += dlen;
-
- } while (xpos < width_);
+ }
}
}
More information about the Scummvm-git-logs
mailing list