[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