Initial commit
This commit is contained in:
288
engines/qdengine/system/graphics/UI_TextParser.cpp
Normal file
288
engines/qdengine/system/graphics/UI_TextParser.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/UI_TextParser.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
UI_TextParser::UI_TextParser(const grFont *font) : _font(font) {
|
||||
_outNodes.reserve(8);
|
||||
init();
|
||||
}
|
||||
|
||||
UI_TextParser::UI_TextParser(const UI_TextParser &src) {
|
||||
(*this) = src;
|
||||
}
|
||||
|
||||
void UI_TextParser::operator= (const UI_TextParser &src) {
|
||||
_font = src._font;
|
||||
|
||||
_outNodes.reserve(8);
|
||||
init();
|
||||
}
|
||||
|
||||
void UI_TextParser::init() {
|
||||
_tagWidth = 0;
|
||||
_lineWidth = 0;
|
||||
|
||||
_lineBegin = 0;
|
||||
_pstr = 0;
|
||||
|
||||
_fitIn = -1;
|
||||
_lastSpace = 0;
|
||||
_lastTagWidth = 0;
|
||||
|
||||
_outNodes.clear();
|
||||
_outNodes.push_back(OutNode());
|
||||
_prevLineIndex = _outNodes.size() - 1;
|
||||
|
||||
_size.set(0, fontHeight());
|
||||
|
||||
_lineCount = 1;
|
||||
}
|
||||
|
||||
void UI_TextParser::setFont(const grFont *font) {
|
||||
_font = font;
|
||||
init();
|
||||
}
|
||||
|
||||
OutNodes::const_iterator UI_TextParser::getLineBegin(int lineNum) const {
|
||||
assert(lineNum >= 0);
|
||||
|
||||
if (!lineNum)
|
||||
return _outNodes.begin();
|
||||
|
||||
if (lineNum >= _lineCount)
|
||||
return _outNodes.end();
|
||||
|
||||
for (auto it = _outNodes.begin(); it != _outNodes.end(); it++) {
|
||||
if (it->type == OutNode::NEW_LINE)
|
||||
if (lineNum-- == 0)
|
||||
return it;
|
||||
}
|
||||
|
||||
assert(lineNum == 0);
|
||||
return _outNodes.end();
|
||||
}
|
||||
|
||||
bool UI_TextParser::testWidth(int width) {
|
||||
if (_fitIn < 0)
|
||||
return true;
|
||||
|
||||
if (_lineWidth + _tagWidth + width > _fitIn) {
|
||||
if (_lastSpace != _lineBegin) {
|
||||
_outNodes.push_back(OutNode(_lineBegin, _lastSpace, _lastTagWidth));
|
||||
|
||||
_lineWidth += _lastTagWidth;
|
||||
endLine();
|
||||
|
||||
_lineBegin = _lastSpace + 1;
|
||||
_lastSpace = _lineBegin;
|
||||
_tagWidth -= _lastTagWidth;
|
||||
_lastTagWidth = 0;
|
||||
} else if (_lineWidth > 0) {
|
||||
assert(_lastTagWidth == 0);
|
||||
endLine();
|
||||
testWidth(width);
|
||||
} else if (_tagWidth > 0) {
|
||||
putText();
|
||||
endLine();
|
||||
skipNode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UI_TextParser::parseString(const char *text, int color, int fitIn) {
|
||||
if (!_font)
|
||||
setFont(grDispatcher::get_default_font());
|
||||
|
||||
assert(_font);
|
||||
init();
|
||||
|
||||
_fitIn = fitIn > 2 * fontHeight() ? fitIn : -1;
|
||||
|
||||
_pstr = text;
|
||||
|
||||
_lineBegin = text;
|
||||
_lastSpace = _lineBegin;
|
||||
|
||||
while (byte cc = *_pstr) {
|
||||
if (cc == '\n') {
|
||||
putText();
|
||||
++_pstr;
|
||||
|
||||
endLine();
|
||||
skipNode();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cc < 32) {
|
||||
++_pstr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cc == ' ') {
|
||||
_lastTagWidth = _tagWidth;
|
||||
_lastSpace = _pstr;
|
||||
}
|
||||
|
||||
//if(useWildChars)
|
||||
if (cc == '&') {
|
||||
if (_pstr[1] != '&') {
|
||||
putText();
|
||||
++_pstr;
|
||||
getColor(color);
|
||||
continue;
|
||||
} else {
|
||||
addChar('&');
|
||||
putText();
|
||||
++_pstr;
|
||||
skipNode();
|
||||
continue;
|
||||
}
|
||||
} else if (cc == '<') {
|
||||
if (_pstr[1] != '<') {
|
||||
putText();
|
||||
++_pstr;
|
||||
_lineWidth += getToken();
|
||||
continue;
|
||||
} else {
|
||||
addChar('<');
|
||||
putText();
|
||||
++_pstr;
|
||||
skipNode();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
addChar((byte)cc);
|
||||
}
|
||||
|
||||
putText();
|
||||
_size.x = MAX(_size.x, _lineWidth);
|
||||
_outNodes[_prevLineIndex].width = _lineWidth;
|
||||
|
||||
_size.y = fontHeight() * _lineCount;
|
||||
}
|
||||
|
||||
int UI_TextParser::getToken() {
|
||||
char cc;
|
||||
while ((cc = *_pstr) && cc != '=' && cc != '>')
|
||||
++_pstr;
|
||||
|
||||
if (cc != '>') {
|
||||
while ((cc = *_pstr) && cc != ';' && cc != '>')
|
||||
++_pstr;
|
||||
if (cc == ';') {
|
||||
while ((cc = *_pstr) && cc != '>')
|
||||
++_pstr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cc) {
|
||||
skipNode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* switch(tag_len){
|
||||
case 3:
|
||||
if(!strncmp(begin_tag, "img=", 4)){
|
||||
string img_name(begin_tag + 4, begin_style ? begin_style : _pstr);
|
||||
if(const UI_Sprite* sprite = UI_SpriteReference(img_name.c_str()))
|
||||
if(!sprite->isEmpty()){
|
||||
OutNode node;
|
||||
node.type = OutNode::SPRITE;
|
||||
node.sprite = sprite;
|
||||
node.style = getStyle(begin_style, _pstr);
|
||||
if((node.style & 0x03) != 2)
|
||||
node.width = sprite->size().xi();
|
||||
else{
|
||||
Vect2f size = sprite->size();
|
||||
node.width = round(size.x / size.y * fontHeight());
|
||||
}
|
||||
++_pstr;
|
||||
testWidth(node.width);
|
||||
putNode(node);
|
||||
return node.width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}*/
|
||||
|
||||
++_pstr;
|
||||
skipNode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UI_TextParser::getStyle(const char *styleptr, const char *end) {
|
||||
if (!styleptr || *end != '>')
|
||||
return 0;
|
||||
|
||||
char cc;
|
||||
while ((cc = *(++styleptr)) && cc != '=' && cc != '>');
|
||||
|
||||
if (cc != '=')
|
||||
return 0;
|
||||
|
||||
int style = 0;
|
||||
while ((cc = *(++styleptr)) >= '0' && cc <= '9')
|
||||
style = style * 10 + (int)(cc - '0');
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
void UI_TextParser::getColor(int defColor) {
|
||||
int color = defColor;
|
||||
|
||||
if (*_pstr != '>') {
|
||||
int s = 0;
|
||||
int i = 0;
|
||||
for (; i < 6; ++i, ++_pstr)
|
||||
if (char k = *_pstr) {
|
||||
int a = fromHex(k);
|
||||
if (a < 0)
|
||||
break;
|
||||
s |= a << (i * 4);
|
||||
} else
|
||||
break;
|
||||
|
||||
if (i > 5) {
|
||||
color &= 0xFF000000;
|
||||
color |= s;
|
||||
} else {
|
||||
skipNode();
|
||||
return;
|
||||
}
|
||||
} else
|
||||
++_pstr;
|
||||
|
||||
OutNode node(color);
|
||||
putNode(node);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
161
engines/qdengine/system/graphics/UI_TextParser.h
Normal file
161
engines/qdengine/system/graphics/UI_TextParser.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_UI_TEXT_PARSER_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_UI_TEXT_PARSER_H
|
||||
|
||||
|
||||
#include "qdengine/system/graphics/gr_font.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
struct OutNode {
|
||||
enum {
|
||||
NEW_LINE,
|
||||
TEXT,
|
||||
COLOR
|
||||
} type;
|
||||
int width;
|
||||
union {
|
||||
struct {
|
||||
const char *begin;
|
||||
const char *end;
|
||||
} nl;
|
||||
struct {
|
||||
int style;
|
||||
} t;
|
||||
int color;
|
||||
};
|
||||
OutNode() : type(NEW_LINE), width(0) { nl.begin = 0; nl.end = 0; }
|
||||
OutNode(const char *b, const char *e, int wd) : type(TEXT), width(wd) { nl.begin = b; nl.end = e; }
|
||||
OutNode(int clr) : type(COLOR), width(0), color(clr) {}
|
||||
};
|
||||
|
||||
typedef Std::vector<OutNode> OutNodes;
|
||||
|
||||
class UI_TextParser {
|
||||
public:
|
||||
UI_TextParser(const grFont *font = 0);
|
||||
UI_TextParser(const UI_TextParser &src);
|
||||
|
||||
void operator= (const UI_TextParser &src);
|
||||
|
||||
void setFont(const grFont *font);
|
||||
|
||||
void parseString(const char *text, int color = 0, int fitIn = -1);
|
||||
|
||||
const OutNodes &outNodes() const {
|
||||
return _outNodes;
|
||||
}
|
||||
|
||||
int fontHeight() const {
|
||||
return _font ? _font->size_y() : 1;
|
||||
}
|
||||
const Vect2i &size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
int lineCount() const {
|
||||
return _lineCount;
|
||||
}
|
||||
OutNodes::const_iterator getLineBegin(int lineNum) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
inline int fromHex(char a) {
|
||||
if (a >= '0' && a <= '9')
|
||||
return a - '0';
|
||||
if (a >= 'A' && a <= 'F')
|
||||
return a - 'A' + 10;
|
||||
if (a >= 'a' && a <= 'f')
|
||||
return a - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline void addChar(byte cc) {
|
||||
int width = _font->char_width(cc);
|
||||
if (testWidth(width) || cc != ' ')
|
||||
_tagWidth += width;
|
||||
++_pstr;
|
||||
}
|
||||
|
||||
inline void skipNode() {
|
||||
_lineBegin = _pstr;
|
||||
_lastSpace = _lineBegin;
|
||||
_lastTagWidth = 0;
|
||||
_tagWidth = 0;
|
||||
}
|
||||
|
||||
inline void putNode(OutNode &node) {
|
||||
_outNodes.push_back(node);
|
||||
skipNode();
|
||||
}
|
||||
|
||||
void putText() {
|
||||
if (_pstr == _lineBegin)
|
||||
return;
|
||||
_lineWidth += _tagWidth;
|
||||
OutNode node(_lineBegin, _pstr, _tagWidth);
|
||||
putNode(node);
|
||||
}
|
||||
|
||||
void endLine() {
|
||||
_size.x = MAX(_size.x, _lineWidth);
|
||||
|
||||
_outNodes[_prevLineIndex].width = _lineWidth;
|
||||
_lineWidth = 0;
|
||||
|
||||
_outNodes.push_back(OutNode());
|
||||
_prevLineIndex = _outNodes.size() - 1;
|
||||
|
||||
++_lineCount;
|
||||
}
|
||||
|
||||
void getColor(int defColor);
|
||||
int getStyle(const char *styleptr, const char *end);
|
||||
int getToken();
|
||||
bool testWidth(int width);
|
||||
|
||||
OutNodes _outNodes;
|
||||
|
||||
int _prevLineIndex;
|
||||
const char *_lastSpace;
|
||||
int _lastTagWidth;
|
||||
|
||||
const char *_lineBegin;
|
||||
const char *_pstr;
|
||||
int _tagWidth;
|
||||
int _lineWidth;
|
||||
|
||||
int _fitIn;
|
||||
|
||||
Vect2i _size;
|
||||
int _lineCount;
|
||||
|
||||
const grFont *_font;
|
||||
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_UI_TEXT_PARSER_H
|
||||
1124
engines/qdengine/system/graphics/gr_dispatcher.cpp
Normal file
1124
engines/qdengine/system/graphics/gr_dispatcher.cpp
Normal file
File diff suppressed because it is too large
Load Diff
598
engines/qdengine/system/graphics/gr_dispatcher.h
Normal file
598
engines/qdengine/system/graphics/gr_dispatcher.h
Normal file
@@ -0,0 +1,598 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_GR_DISPATCHER_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_GR_DISPATCHER_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
// Directions for LineTo()
|
||||
enum GR_LINEDIR {
|
||||
GR_LEFT,
|
||||
GR_TOP,
|
||||
GR_RIGHT,
|
||||
GR_BOTTOM
|
||||
};
|
||||
|
||||
// Modes for putSpr()
|
||||
const int GR_BLACK_FON = 0x01;
|
||||
const int GR_CLIPPED = 0x02;
|
||||
const int GR_NOCLIP = 0x04;
|
||||
const int GR_FLIP_HORIZONTAL = 0x08;
|
||||
const int GR_FLIP_VERTICAL = 0x10;
|
||||
const int GR_IGNORE_ALPHA = 0x20;
|
||||
|
||||
// Modes for Rectangle()
|
||||
const int GR_FILLED = 0x00;
|
||||
const int GR_OUTLINED = 0x01;
|
||||
|
||||
// grDispatcher::_flags
|
||||
const int GR_INITED = 0x01;
|
||||
const int GR_PALETTE = 0x02;
|
||||
const int GR_REINIT = 0x04;
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
typedef int16 zbuf_t;
|
||||
const GR_ZBUFFFER_MASK = 0xFFFF;
|
||||
const GR_ZBUFFER_MAX_Z = 30000;
|
||||
#endif
|
||||
|
||||
enum grTextAlign {
|
||||
GR_ALIGN_LEFT,
|
||||
GR_ALIGN_CENTER,
|
||||
GR_ALIGN_RIGHT
|
||||
};
|
||||
|
||||
enum grPixelFormat {
|
||||
GR_RGB565 = 0,
|
||||
GR_ARGB1555,
|
||||
GR_RGB888,
|
||||
GR_ARGB8888,
|
||||
GR_RGBA8888
|
||||
};
|
||||
|
||||
class grFont;
|
||||
class grTileSprite;
|
||||
class RLEBuffer;
|
||||
class UI_TextParser;
|
||||
|
||||
class grDispatcher {
|
||||
public:
|
||||
grDispatcher();
|
||||
virtual ~grDispatcher();
|
||||
|
||||
static bool sys_init();
|
||||
|
||||
bool init(int sx, int sy, grPixelFormat pixel_format);
|
||||
|
||||
void toggle_reinit() {
|
||||
_flags |= GR_REINIT;
|
||||
}
|
||||
bool is_in_reinit_mode() const {
|
||||
return _flags & GR_REINIT;
|
||||
}
|
||||
|
||||
void set_flag(int fl) {
|
||||
_flags |= fl;
|
||||
}
|
||||
void drop_flag(int fl) {
|
||||
_flags &= ~fl;
|
||||
}
|
||||
bool check_flag(int fl) {
|
||||
if (_flags & fl) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool finit();
|
||||
|
||||
void *Get_hWnd() const {
|
||||
return _hWnd;
|
||||
}
|
||||
int get_SizeX() const {
|
||||
return _sizeX;
|
||||
}
|
||||
int get_SizeY() const {
|
||||
return _sizeY;
|
||||
}
|
||||
|
||||
void setClipMode(int m) {
|
||||
_clipMode = m;
|
||||
}
|
||||
int getClipMode() const {
|
||||
return _clipMode;
|
||||
}
|
||||
|
||||
void setClip() {
|
||||
setClip(0, 0, _sizeX, _sizeY);
|
||||
}
|
||||
|
||||
void getClip(int &l, int &t, int &r, int &b) const {
|
||||
l = _clipCoords[GR_LEFT];
|
||||
t = _clipCoords[GR_TOP];
|
||||
r = _clipCoords[GR_RIGHT];
|
||||
b = _clipCoords[GR_BOTTOM];
|
||||
}
|
||||
|
||||
void setClip(int l, int t, int r, int b) {
|
||||
if (l < 0) l = 0;
|
||||
if (r > _sizeX) r = _sizeX;
|
||||
|
||||
if (t < 0) t = 0;
|
||||
if (b > _sizeY) b = _sizeY;
|
||||
|
||||
_clipCoords[GR_LEFT] = l;
|
||||
_clipCoords[GR_TOP] = t;
|
||||
_clipCoords[GR_RIGHT] = r;
|
||||
_clipCoords[GR_BOTTOM] = b;
|
||||
}
|
||||
|
||||
void limitClip(int l, int t, int r, int b) {
|
||||
if (_clipCoords[GR_LEFT] < l) _clipCoords[GR_LEFT] = l;
|
||||
if (_clipCoords[GR_TOP] < t) _clipCoords[GR_TOP] = t;
|
||||
if (_clipCoords[GR_RIGHT] > r) _clipCoords[GR_RIGHT] = r;
|
||||
if (_clipCoords[GR_BOTTOM] > b) _clipCoords[GR_BOTTOM] = b;
|
||||
}
|
||||
|
||||
int clipCheck(int x, int y) {
|
||||
if (x >= _clipCoords[GR_LEFT] && x < _clipCoords[GR_RIGHT] && y >= _clipCoords[GR_TOP] && y < _clipCoords[GR_BOTTOM])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clipCheck(int x, int y, int sx, int sy) {
|
||||
if (x - sx >= _clipCoords[GR_LEFT] && x + sx < _clipCoords[GR_RIGHT] && y - sy >= _clipCoords[GR_TOP] && y + sy < _clipCoords[GR_BOTTOM])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool flush(int x, int y, int sx, int sy);
|
||||
bool flush();
|
||||
bool flushChanges();
|
||||
|
||||
void fill(int val);
|
||||
|
||||
void putSpr(int x, int y, int sx, int sy, const byte *p, int mode, int spriteFormat);
|
||||
void putSpr(int x, int y, int sx, int sy, const byte *p, int mode, int spriteFormat, float scale);
|
||||
void putSpr_rle(int x, int y, int sx, int sy, const RLEBuffer *p, int mode, bool alpha_flag);
|
||||
void putSpr_rle(int x, int y, int sx, int sy, const RLEBuffer *p, int mode, float scale, bool alpha_flag);
|
||||
void putSpr_a(int x, int y, int sx, int sy, const byte *p, int mode);
|
||||
void putSpr_a(int x, int y, int sx, int sy, const byte *p, int mode, float scale);
|
||||
|
||||
void putSpr_rot(const Vect2i &pos, const Vect2i &size, const byte *data, bool has_alpha, int mode, float angle);
|
||||
void putSpr_rot(const Vect2i &pos, const Vect2i &size, const byte *data, bool has_alpha, int mode, float angle, const Vect2f &scale);
|
||||
void putSpr_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, int mode, float angle);
|
||||
void putSpr_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, int mode, float angle, const Vect2f &scale);
|
||||
|
||||
void putSprMask_rot(const Vect2i &pos, const Vect2i &size, const byte *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle);
|
||||
void putSprMask_rot(const Vect2i &pos, const Vect2i &size, const byte *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle, const Vect2f &scale);
|
||||
void putSprMask_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle);
|
||||
void putSprMask_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle, const Vect2f &scale);
|
||||
|
||||
void putSprMask(int x, int y, int sx, int sy, const byte *p, uint32 mask_color, int mask_alpha, int mode);
|
||||
void putSprMask(int x, int y, int sx, int sy, const byte *p, uint32 mask_color, int mask_alpha, int mode, float scale);
|
||||
void putSprMask_rle(int x, int y, int sx, int sy, const RLEBuffer *p, uint32 mask_color, int mask_alpha, int mode, bool alpha_flag);
|
||||
void putSprMask_rle(int x, int y, int sx, int sy, const RLEBuffer *p, uint32 mask_color, int mask_alpha, int mode, float scale, bool alpha_flag);
|
||||
void putSprMask_a(int x, int y, int sx, int sy, const byte *p, uint32 mask_color, int mask_alpha, int mode);
|
||||
void putSprMask_a(int x, int y, int sx, int sy, const byte *p, uint32 mask_color, int mask_alpha, int mode, float scale);
|
||||
|
||||
void putTileSpr(int x, int y, const grTileSprite &sprite, bool has_alpha, int mode, Graphics::ManagedSurface *surface = nullptr, bool clip = true);
|
||||
|
||||
void putChar(int x, int y, uint32 color, int font_sx, int font_sy, const byte *font_alpha, const grScreenRegion &char_region);
|
||||
|
||||
void drawSprContour_a(int x, int y, int sx, int sy, const byte *p, int contour_color, int mode);
|
||||
void drawSprContour_a(int x, int y, int sx, int sy, const byte *p, int contour_color, int mode, float scale);
|
||||
void drawSprContour(int x, int y, int sx, int sy, const byte *p, int contour_color, int mode);
|
||||
void drawSprContour(int x, int y, int sx, int sy, const byte *p, int contour_color, int mode, float scale);
|
||||
void drawSprContour(int x, int y, int sx, int sy, const RLEBuffer *p, int contour_color, int mode, bool alpha_flag);
|
||||
void drawSprContour(int x, int y, int sx, int sy, const RLEBuffer *p, int contour_color, int mode, float scale, bool alpha_flag);
|
||||
|
||||
bool drawText(int x, int y, uint32 color, const char *str, int hspace = 0, int vspace = 0, const grFont *font = NULL);
|
||||
bool drawAlignedText(int x, int y, int sx, int sy, uint32 color, const char *str, grTextAlign align = GR_ALIGN_LEFT, int hspace = 0, int vspace = 0, const grFont *font = NULL);
|
||||
bool drawParsedText(int x, int y, int sx, int sy, uint32 color, const UI_TextParser *parser, grTextAlign align = GR_ALIGN_LEFT, const grFont *font = NULL);
|
||||
int textWidth(const char *str, int hspace = 0, const grFont *font = NULL, bool first_string_only = false) const;
|
||||
int textHeight(const char *str, int vspace = 0, const grFont *font = NULL) const;
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
void putSpr_z(int x, int y, int z, int sx, int sy, const byte *p, int mode);
|
||||
void putSpr_z(int x, int y, int z, int sx, int sy, const byte *p, int mode, float scale);
|
||||
void putSpr_rle_z(int x, int y, int z, int sx, int sy, const RLEBuffer *p, int mode, bool alpha_flag);
|
||||
void putSpr_rle_z(int x, int y, int z, int sx, int sy, const RLEBuffer *p, int mode, float scale, bool alpha_flag);
|
||||
void putSpr_a_z(int x, int y, int z, int sx, int sy, const byte *p, int mode);
|
||||
void putSpr_a_z(int x, int y, int z, int sx, int sy, const byte *p, int mode, float scale);
|
||||
#endif
|
||||
|
||||
void erase(int x, int y, int sx, int sy, int col);
|
||||
void erase(int x, int y, int sx, int sy, int r, int g, int b);
|
||||
|
||||
void setPixel(int x, int y, int col);
|
||||
void setPixelFast(byte *buf, uint32 col);
|
||||
void setPixelFast(int x, int y, int col);
|
||||
void setPixelFast(int x, int y, int r, int g, int b);
|
||||
|
||||
void setPixel(int x, int y, int r, int g, int b);
|
||||
|
||||
void surfaceOverride(Graphics::ManagedSurface *target);
|
||||
void resetSurfaceOverride();
|
||||
|
||||
void getPixel(int x, int y, uint32 &col);
|
||||
void getPixel(int x, int y, uint16 &col);
|
||||
void getPixel(int x, int y, byte &r, byte &g, byte &b);
|
||||
|
||||
void line(int x1, int y1, int x2, int y2, int col, int line_style = 0, bool inverse_col = false);
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
void line_z(int x1, int y1, int z1, int x2, int y2, int z2, int col, int line_style = 0);
|
||||
#endif
|
||||
|
||||
void lineTo(int x, int y, int len, int dir, int col, int line_style = 0);
|
||||
void rectangle(int x, int y, int sx, int sy, int outcol, int incol, int mode, int line_style = 0);
|
||||
void rectangleAlpha(int x, int y, int sx, int sy, uint32 color, int alpha);
|
||||
|
||||
int PalettedMode() const {
|
||||
return (_flags & GR_PALETTE);
|
||||
}
|
||||
|
||||
grPixelFormat pixel_format() const {
|
||||
return _pixel_format;
|
||||
}
|
||||
void set_pixel_format(grPixelFormat mode) {
|
||||
_pixel_format = GR_RGB565;
|
||||
}
|
||||
|
||||
inline int bytes_per_pixel() const {
|
||||
switch (_pixel_format) {
|
||||
case GR_ARGB1555:
|
||||
case GR_RGB565:
|
||||
return 2;
|
||||
case GR_RGB888:
|
||||
return 3;
|
||||
case GR_ARGB8888:
|
||||
case GR_RGBA8888:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum { // маски для high color режимов
|
||||
mask_565_r = 0xFFFF & (0x001F << 11),
|
||||
mask_565_g = 0xFFFF & (0x003F << 5),
|
||||
mask_565_b = 0xFFFF & (0x001F << 0),
|
||||
|
||||
mask_555_r = 0xFFFF & (0x001F << 10),
|
||||
mask_555_g = 0xFFFF & (0x001F << 5),
|
||||
mask_555_b = 0xFFFF & (0x001F << 0)
|
||||
};
|
||||
|
||||
inline uint32 make_rgb(uint32 color) const {
|
||||
switch (_pixel_format) {
|
||||
case GR_RGB565:
|
||||
return make_rgb565u((color >> 0) & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);
|
||||
case GR_ARGB1555:
|
||||
return make_rgb555u((color >> 0) & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);
|
||||
case GR_RGB888:
|
||||
case GR_ARGB8888:
|
||||
case GR_RGBA8888:
|
||||
return color;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline uint32 make_rgb(uint32 r, uint32 g, uint32 b) const {
|
||||
switch (_pixel_format) {
|
||||
case GR_RGB565:
|
||||
return make_rgb565u(r, g, b);
|
||||
case GR_ARGB1555:
|
||||
return make_rgb555u(r, g, b);
|
||||
case GR_RGB888:
|
||||
case GR_ARGB8888:
|
||||
return ((b << 16) | (g << 8) | r);
|
||||
case GR_RGBA8888:
|
||||
return ((r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// Обработчик ввода символа
|
||||
typedef bool (*char_input_hanler_t)(int input);
|
||||
static char_input_hanler_t set_input_handler(char_input_hanler_t h) {
|
||||
char_input_hanler_t old_h = _input_handler;
|
||||
_input_handler = h;
|
||||
return old_h;
|
||||
}
|
||||
|
||||
static bool handle_char_input(int input) {
|
||||
if (_input_handler) return (*_input_handler)(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline uint32 make_rgb888(uint32 r, uint32 g, uint32 b) {
|
||||
return ((b << 16) | (g << 8) | r);
|
||||
}
|
||||
|
||||
static inline uint16 make_rgb565u(uint32 r, uint32 g, uint32 b) {
|
||||
return (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));
|
||||
}
|
||||
static inline uint16 make_rgb555u(uint32 r, uint32 g, uint32 b) {
|
||||
return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3) << 0));
|
||||
}
|
||||
|
||||
static inline void split_rgb565u(uint32 col, byte &r, byte &g, byte &b) {
|
||||
r = ((col & mask_565_r) >> 11) << 3;
|
||||
g = ((col & mask_565_g) >> 5) << 2;
|
||||
b = ((col & mask_565_b) >> 0) << 3;
|
||||
}
|
||||
static inline void split_rgb555u(uint32 col, byte &r, byte &g, byte &b) {
|
||||
r = ((col & mask_555_r) >> 10) << 3;
|
||||
g = ((col & mask_555_g) >> 5) << 3;
|
||||
b = ((col & mask_555_b) >> 0) << 3;
|
||||
}
|
||||
|
||||
static inline void split_rgb888(uint32 col, byte &r, byte &g, byte &b) {
|
||||
r = (col >> 0) & 0xFF;
|
||||
g = (col >> 8) & 0xFF;
|
||||
b = (col >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
static inline uint16 make_rgb565(uint32 r, uint32 g, uint32 b) {
|
||||
return ((r << 11) | (g << 5) | (b << 0));
|
||||
}
|
||||
static inline uint16 make_rgb555(uint32 r, uint32 g, uint32 b) {
|
||||
return ((r << 10) | (g << 5) | (b << 0));
|
||||
}
|
||||
|
||||
static inline uint16 alpha_blend_565(uint16 pic_col, uint16 scr_col, uint32 a) {
|
||||
if (a != 255) {
|
||||
if (a)
|
||||
return pic_col + (((((scr_col & mask_565_r) * a) >> 8) & mask_565_r) |
|
||||
((((scr_col & mask_565_g) * a) >> 8) & mask_565_g) |
|
||||
((((scr_col & mask_565_b) * a) >> 8) & mask_565_b));
|
||||
else
|
||||
return pic_col;
|
||||
} else
|
||||
return scr_col;
|
||||
}
|
||||
|
||||
static inline uint16 alpha_blend_555(uint16 pic_col, uint16 scr_col, uint32 a) {
|
||||
if (a != 255) {
|
||||
if (a)
|
||||
return pic_col + (((((scr_col & mask_555_r) * a) >> 8) & mask_555_r) |
|
||||
((((scr_col & mask_555_g) * a) >> 8) & mask_555_g) |
|
||||
((((scr_col & mask_555_b) * a) >> 8) & mask_555_b));
|
||||
else
|
||||
return pic_col;
|
||||
} else
|
||||
return scr_col;
|
||||
}
|
||||
|
||||
const void *mouse_cursor() const {
|
||||
return _mouse_cursor;
|
||||
}
|
||||
void set_default_mouse_cursor() {
|
||||
_mouse_cursor = _default_mouse_cursor;
|
||||
}
|
||||
void set_null_mouse_cursor() {
|
||||
_mouse_cursor = NULL;
|
||||
}
|
||||
|
||||
static grDispatcher *instance(void *hwnd);
|
||||
|
||||
bool is_mouse_hidden() const {
|
||||
return _hide_mouse;
|
||||
}
|
||||
void hideMouse() {
|
||||
_hide_mouse = true;
|
||||
}
|
||||
void showMouse() {
|
||||
_hide_mouse = false;
|
||||
}
|
||||
|
||||
bool clip_line(int &x0, int &y0, int &x1, int &y1) const;
|
||||
bool clip_line(int &x0, int &y0, int &z0, int &x1, int &y1, int &z1) const;
|
||||
bool clip_rectangle(int &x, int &y, int &pic_x, int &pic_y, int &pic_sx, int &pic_sy) const;
|
||||
|
||||
bool is_rectangle_visible(int x, int y, int sx, int sy) const {
|
||||
if (x + sx < 0 || x >= _sizeX || y + sy < 0 || y >= _sizeY) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool clip_rectangle(int &x, int &y, int &sx, int &sy) const {
|
||||
int x1 = x + sx;
|
||||
int y1 = y + sy;
|
||||
|
||||
if (x < _clipCoords[0]) x = _clipCoords[0];
|
||||
if (x1 >= _clipCoords[2]) x1 = _clipCoords[2] - 1;
|
||||
|
||||
if (y < _clipCoords[1]) y = _clipCoords[1];
|
||||
if (y1 >= _clipCoords[3]) y1 = _clipCoords[3] - 1;
|
||||
|
||||
sx = x1 - x;
|
||||
sy = y1 - y;
|
||||
|
||||
if (sx <= 0 || sy <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear_changes_mask();
|
||||
|
||||
typedef Std::vector<grScreenRegion> regions_container_t;
|
||||
typedef regions_container_t::const_iterator region_iterator;
|
||||
|
||||
const regions_container_t &changed_regions() const {
|
||||
return _changed_regions;
|
||||
}
|
||||
void build_changed_regions();
|
||||
bool invalidate_region(const grScreenRegion ®);
|
||||
|
||||
static inline grDispatcher *instance() {
|
||||
return _dispatcher_ptr;
|
||||
}
|
||||
static inline grDispatcher *set_instance(grDispatcher *p) {
|
||||
grDispatcher *old_p = _dispatcher_ptr;
|
||||
_dispatcher_ptr = p;
|
||||
return old_p;
|
||||
}
|
||||
|
||||
static inline const char *wnd_class_name() {
|
||||
return _wnd_class_name;
|
||||
}
|
||||
|
||||
typedef void (*restore_handler_t)();
|
||||
static restore_handler_t set_restore_handler(restore_handler_t h) {
|
||||
restore_handler_t old_h = _restore_handler;
|
||||
_restore_handler = h;
|
||||
return old_h;
|
||||
}
|
||||
|
||||
static bool is_active() {
|
||||
return _is_active;
|
||||
}
|
||||
static void activate(bool state) {
|
||||
if (state && !_is_active) {
|
||||
if (_restore_handler)
|
||||
(*_restore_handler)();
|
||||
}
|
||||
_is_active = state;
|
||||
}
|
||||
|
||||
char *temp_buffer(int size);
|
||||
|
||||
static bool convert_sprite(grPixelFormat src_fmt, grPixelFormat &dest_fmt, int sx, int sy, byte *data, bool &has_alpha);
|
||||
|
||||
static grFont *load_font(const char *file_name);
|
||||
static void set_default_font(grFont *p) {
|
||||
_default_font = p;
|
||||
}
|
||||
static grFont *get_default_font() {
|
||||
return _default_font;
|
||||
}
|
||||
protected:
|
||||
|
||||
int _flags;
|
||||
|
||||
int _wndPosX;
|
||||
int _wndPosY;
|
||||
int _wndSizeX;
|
||||
int _wndSizeY;
|
||||
|
||||
int _sizeX;
|
||||
int _sizeY;
|
||||
|
||||
grPixelFormat _pixel_format;
|
||||
void *_hWnd;
|
||||
|
||||
Graphics::ManagedSurface *_screenBuf = nullptr;
|
||||
Graphics::ManagedSurface *_realScreenBuf = nullptr;
|
||||
|
||||
char *_temp_buffer;
|
||||
int _temp_buffer_size;
|
||||
|
||||
private:
|
||||
|
||||
int _clipMode;
|
||||
int _clipCoords[4];
|
||||
|
||||
bool _hide_mouse;
|
||||
void *_mouse_cursor;
|
||||
static void *_default_mouse_cursor;
|
||||
|
||||
enum {
|
||||
clLEFT = 1,
|
||||
clRIGHT = 2,
|
||||
clBOTTOM = 4,
|
||||
clTOP = 8
|
||||
};
|
||||
|
||||
inline int clip_out_code(int x, int y) const {
|
||||
int code = 0;
|
||||
if (y >= _clipCoords[3])
|
||||
code |= clTOP;
|
||||
else if (y < _clipCoords[1])
|
||||
code |= clBOTTOM;
|
||||
if (x >= _clipCoords[2])
|
||||
code |= clRIGHT;
|
||||
else if (x < _clipCoords[0])
|
||||
code |= clLEFT;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
zbuf_t *zbuffer_;
|
||||
|
||||
bool alloc_zbuffer(int sx, int sy);
|
||||
bool free_zbuffer();
|
||||
bool clear_zbuffer();
|
||||
|
||||
zbuf_t get_z(int x, int y) {
|
||||
return zbuffer_[x + y * _sizeX];
|
||||
}
|
||||
void put_z(int x, int y, int z) {
|
||||
zbuffer_[x + y * _sizeX] = z;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef Std::vector<char> changes_mask_t;
|
||||
|
||||
enum {
|
||||
kChangesMaskTile = 16,
|
||||
kChangesMaskTileShift = 4
|
||||
};
|
||||
|
||||
int _changes_mask_size_x;
|
||||
int _changes_mask_size_y;
|
||||
|
||||
changes_mask_t _changes_mask;
|
||||
|
||||
regions_container_t _changed_regions;
|
||||
|
||||
static char_input_hanler_t _input_handler;
|
||||
|
||||
static grFont *_default_font;
|
||||
|
||||
static bool _is_active;
|
||||
static restore_handler_t _restore_handler;
|
||||
|
||||
static grDispatcher *_dispatcher_ptr;
|
||||
static char *_wnd_class_name;
|
||||
|
||||
void putSpr_rot90(const Vect2i &pos, const Vect2i &size, const byte *data, bool has_alpha, int mode, float angle);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_GR_DISPATCHER_H
|
||||
1435
engines/qdengine/system/graphics/gr_draw_sprite.cpp
Normal file
1435
engines/qdengine/system/graphics/gr_draw_sprite.cpp
Normal file
File diff suppressed because it is too large
Load Diff
912
engines/qdengine/system/graphics/gr_draw_sprite_rle.cpp
Normal file
912
engines/qdengine/system/graphics/gr_draw_sprite_rle.cpp
Normal file
@@ -0,0 +1,912 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/rle_compress.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
void grDispatcher::putSpr_rle(int x, int y, int sx, int sy, const class RLEBuffer *p, int mode, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle([%d, %d], [%d, %d], mode: %d, alpha: %d", x, y, sx, sy, mode, alpha_flag);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
int dx = -2;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += (psx - 1);
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 2;
|
||||
|
||||
if (_pixel_format == GR_RGBA8888)
|
||||
dx *= 2;
|
||||
|
||||
psx += px;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(_screenBuf->getBasePtr(x, y));
|
||||
|
||||
const int8 *rle_header = p->header_ptr(py + i);
|
||||
const uint32 *rle_data = p->data_ptr(py + i);
|
||||
|
||||
int j = 0;
|
||||
int8 count = 0;
|
||||
while (j < px) {
|
||||
count = *rle_header++;
|
||||
if (count > 0) {
|
||||
if (count + j <= px) {
|
||||
j += count;
|
||||
rle_data++;
|
||||
count = 0;
|
||||
} else {
|
||||
count -= px - j;
|
||||
j = px;
|
||||
}
|
||||
} else {
|
||||
if (j - count <= px) {
|
||||
j -= count;
|
||||
rle_data -= count;
|
||||
count = 0;
|
||||
} else {
|
||||
count += px - j;
|
||||
rle_data += px - j;
|
||||
j = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alpha_flag) {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 cl = make_rgb(rle_buf[2], rle_buf[1], rle_buf[0]);
|
||||
setPixelFast(scr_buf, cl);
|
||||
}
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 cl = make_rgb(rle_buf[2], rle_buf[1], rle_buf[0]);
|
||||
setPixelFast(scr_buf, cl);
|
||||
}
|
||||
scr_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
} else {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 a = rle_buf[3];
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
*(uint16 *)scr_buf = alpha_blend_565(make_rgb565u(rle_buf[2], rle_buf[1], rle_buf[0]), *(uint16 *)scr_buf, a);
|
||||
} else {
|
||||
if (a != 255) {
|
||||
scr_buf[1] = rle_buf[0] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = rle_buf[1] + ((a * scr_buf[2]) >> 8);
|
||||
scr_buf[3] = rle_buf[2] + ((a * scr_buf[3]) >> 8);
|
||||
}
|
||||
}
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 a = rle_buf[3];
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
*(uint16 *)scr_buf = alpha_blend_565(make_rgb565u(rle_buf[2], rle_buf[1], rle_buf[0]), *(uint16 *)scr_buf, a);
|
||||
} else {
|
||||
if (a != 255) {
|
||||
scr_buf[1] = rle_buf[0] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = rle_buf[1] + ((a * scr_buf[2]) >> 8);
|
||||
scr_buf[3] = rle_buf[2] + ((a * scr_buf[3]) >> 8);
|
||||
}
|
||||
}
|
||||
scr_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_rle(int x, int y, int sx, int sy, const class RLEBuffer *p, int mode, float scale, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle([%d, %d], [%d, %d], mode: %d, scale: %f, alpha: %d", x, y, sx, sy, mode, scale, alpha_flag);
|
||||
|
||||
int sx_dest = round(float(sx) * scale);
|
||||
int sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (sx_dest <= 0 || sy_dest <= 0) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest - 1;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest - 1;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest - 1,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest - 1,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
if (!alpha_flag) {
|
||||
const byte *line_src = RLEBuffer::get_buffer(0);
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
const byte *src_data = line_src + (fx >> 16) * 3;
|
||||
if (src_data[0] || src_data[1] || src_data[2])
|
||||
setPixelFast(x + j, y + i, make_rgb(src_data[2], src_data[1], src_data[0]));
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const byte *line_src = RLEBuffer::get_buffer(0);
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
const byte *src_data = line_src + ((fx >> 16) << 2);
|
||||
|
||||
uint32 a = src_data[3];
|
||||
if (a != 255) {
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
uint32 cl = make_rgb565u(src_data[2], src_data[1], src_data[0]);
|
||||
|
||||
if (a) {
|
||||
uint16 scl;
|
||||
getPixel(x + j, y + i, scl);
|
||||
|
||||
setPixelFast(x + j, y + i, alpha_blend_565(cl, scl, a));
|
||||
} else
|
||||
setPixelFast(x + j, y + i, cl);
|
||||
} else {
|
||||
byte sr, sg, sb;
|
||||
getPixel(x + j, y + i, sr, sg, sb);
|
||||
|
||||
uint32 r = src_data[2] + ((a * sr) >> 8);
|
||||
uint32 g = src_data[1] + ((a * sg) >> 8);
|
||||
uint32 b = src_data[0] + ((a * sb) >> 8);
|
||||
|
||||
setPixelFast(x + j, y + i, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSprMask_rle(int x, int y, int sx, int sy, const RLEBuffer *p, uint32 mask_color, int mask_alpha, int mode, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSprMask_rle([%d, %d], [%d, %d], ...)", x, y, sx, sy);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
|
||||
int dx = -2;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += (psx - 1);
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 2;
|
||||
|
||||
if (_pixel_format == GR_RGBA8888)
|
||||
dx *= 2;
|
||||
|
||||
psx += px;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(_screenBuf->getBasePtr(x, y));
|
||||
|
||||
const int8 *rle_header = p->header_ptr(py + i);
|
||||
const uint32 *rle_data = p->data_ptr(py + i);
|
||||
|
||||
int j = 0;
|
||||
int8 count = 0;
|
||||
while (j < px) {
|
||||
count = *rle_header++;
|
||||
if (count > 0) {
|
||||
if (count + j <= px) {
|
||||
j += count;
|
||||
rle_data++;
|
||||
count = 0;
|
||||
} else {
|
||||
count -= px - j;
|
||||
j = px;
|
||||
}
|
||||
} else {
|
||||
if (j - count <= px) {
|
||||
j -= count;
|
||||
rle_data -= count;
|
||||
count = 0;
|
||||
} else {
|
||||
count += px - j;
|
||||
rle_data += px - j;
|
||||
j = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
byte mr, mg, mb;
|
||||
if (_pixel_format == GR_RGB565)
|
||||
split_rgb565u(mask_color, mr, mg, mb);
|
||||
else
|
||||
split_rgb888(mask_color, mr, mg, mb);
|
||||
|
||||
if (!alpha_flag) {
|
||||
mr = (mr * (255 - mask_alpha)) >> 8;
|
||||
mg = (mg * (255 - mask_alpha)) >> 8;
|
||||
mb = (mb * (255 - mask_alpha)) >> 8;
|
||||
|
||||
uint32 cl = make_rgb(mr, mg, mb);
|
||||
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
setPixelFast(scr_buf, cl);
|
||||
} else {
|
||||
scr_buf[3] = mr + ((mask_alpha * scr_buf[3]) >> 8);
|
||||
scr_buf[2] = mg + ((mask_alpha * scr_buf[2]) >> 8);
|
||||
scr_buf[1] = mb + ((mask_alpha * scr_buf[1]) >> 8);
|
||||
}
|
||||
}
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
setPixelFast(scr_buf, cl);
|
||||
} else {
|
||||
scr_buf[3] = mr + ((mask_alpha * scr_buf[3]) >> 8);
|
||||
scr_buf[2] = mg + ((mask_alpha * scr_buf[2]) >> 8);
|
||||
scr_buf[1] = mb + ((mask_alpha * scr_buf[1]) >> 8);
|
||||
}
|
||||
}
|
||||
scr_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
} else {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 a = rle_buf[3];
|
||||
|
||||
if (a != 255) {
|
||||
a = mask_alpha + ((a * (255 - mask_alpha)) >> 8);
|
||||
|
||||
uint32 r = (mr * (255 - a)) >> 8;
|
||||
uint32 g = (mg * (255 - a)) >> 8;
|
||||
uint32 b = (mb * (255 - a)) >> 8;
|
||||
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
uint16 cl = make_rgb565u(r, g, b);
|
||||
*(uint16 *)scr_buf = alpha_blend_565(cl, *(uint16 *)scr_buf, a);
|
||||
} else {
|
||||
scr_buf[1] = b + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = g + ((a * scr_buf[2]) >> 8);
|
||||
scr_buf[3] = r + ((a * scr_buf[3]) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
const byte *rle_buf = (const byte *)rle_data;
|
||||
uint32 a = rle_buf[3];
|
||||
|
||||
if (a != 255) {
|
||||
a = mask_alpha + ((a * (255 - mask_alpha)) >> 8);
|
||||
|
||||
uint32 r = (mr * (255 - a)) >> 8;
|
||||
uint32 g = (mg * (255 - a)) >> 8;
|
||||
uint32 b = (mb * (255 - a)) >> 8;
|
||||
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
uint16 cl = make_rgb565u(r, g, b);
|
||||
*(uint16 *)scr_buf = alpha_blend_565(cl, *(uint16 *)scr_buf, a);
|
||||
} else {
|
||||
scr_buf[1] = b + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = g + ((a * scr_buf[2]) >> 8);
|
||||
scr_buf[3] = r + ((a * scr_buf[3]) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
scr_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSprMask_rle(int x, int y, int sx, int sy, const RLEBuffer *p, uint32 mask_color, int mask_alpha, int mode, float scale, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSprMask_rle([%d, %d], [%d, %d], mask: %d, alpha: %d, mode: %d, scale: %f, alpha_flag: %d)", x, y, sx, sy, mask_color, mask_alpha, mode, scale, alpha_flag);
|
||||
|
||||
int sx_dest = round(float(sx) * scale);
|
||||
int sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (sx_dest <= 0 || sy_dest <= 0) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest - 1;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest - 1;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest - 1,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest - 1,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
if (!alpha_flag) {
|
||||
byte mr, mg, mb;
|
||||
if (_pixel_format == GR_RGB565)
|
||||
split_rgb565u(mask_color, mr, mg, mb);
|
||||
else
|
||||
split_rgb888(mask_color, mr, mg, mb);
|
||||
|
||||
mr = (mr * (255 - mask_alpha)) >> 8;
|
||||
mg = (mg * (255 - mask_alpha)) >> 8;
|
||||
mb = (mb * (255 - mask_alpha)) >> 8;
|
||||
|
||||
uint32 mcl = make_rgb(mr, mg, mb);
|
||||
|
||||
const byte *line_src = RLEBuffer::get_buffer(0);
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
const byte *src_buf = line_src + ((fx >> 16) << 2);
|
||||
if (src_buf[0] || src_buf[1] || src_buf[2]) {
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
uint16 scl;
|
||||
getPixel(x + j, y + i, scl);
|
||||
setPixelFast(x + j, y + i, alpha_blend_565(mcl, scl, mask_alpha));
|
||||
} else {
|
||||
byte sr, sg, sb;
|
||||
getPixel(x + j, y + i, sr, sg, sb);
|
||||
|
||||
uint32 r = mr + ((mask_alpha * sr) >> 8);
|
||||
uint32 g = mg + ((mask_alpha * sg) >> 8);
|
||||
uint32 b = mb + ((mask_alpha * sb) >> 8);
|
||||
|
||||
setPixelFast(x + j, y + i, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const byte *line_src = RLEBuffer::get_buffer(0);
|
||||
byte mr, mg, mb;
|
||||
if (_pixel_format == GR_RGB565)
|
||||
split_rgb565u(mask_color, mr, mg, mb);
|
||||
else
|
||||
split_rgb888(mask_color, mr, mg, mb);
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
const byte *src_buf = line_src + ((fx >> 16) << 2);
|
||||
uint32 a = src_buf[3];
|
||||
if (a != 255) {
|
||||
a = mask_alpha + ((a * (255 - mask_alpha)) >> 8);
|
||||
|
||||
uint32 r = (mr * (255 - a)) >> 8;
|
||||
uint32 g = (mg * (255 - a)) >> 8;
|
||||
uint32 b = (mb * (255 - a)) >> 8;
|
||||
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
uint16 scl;
|
||||
getPixel(x + j, y + i, scl);
|
||||
|
||||
uint16 cl = make_rgb565u(r, g, b);
|
||||
setPixelFast(x + j, y + i, alpha_blend_565(cl, scl, a));
|
||||
} else {
|
||||
byte sr, sg, sb;
|
||||
getPixel(x + j, y + i, sr, sg, sb);
|
||||
|
||||
r = r + ((a * sr) >> 8);
|
||||
g = g + ((a * sg) >> 8);
|
||||
b = b + ((a * sb) >> 8);
|
||||
|
||||
setPixelFast(x + j, y + i, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, int mode, float angle) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_rot([%d, %d], [%d, %d], alpha: %d, mode: %d, angle: %f", pos.x, pos.y, size.x, size.y, has_alpha, mode, angle);
|
||||
|
||||
byte *buf = (byte *)temp_buffer(size.x * size.y * 4);
|
||||
|
||||
byte *buf_ptr = buf;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
data->decode_line(i, buf_ptr);
|
||||
buf_ptr += size.x * 4;
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
uint32 *p = (uint32 *)buf;
|
||||
buf_ptr = buf + 3;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
for (int j = 0; j < size.x; j++) {
|
||||
if (!*p++)
|
||||
*buf_ptr = 255;
|
||||
|
||||
buf_ptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putSpr_rot(pos, size, buf, true, mode, angle);
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, int mode, float angle, const Vect2f &scale) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_rot([%d, %d], [%d, %d], alpha: %d, mode: %d, angle: %f, scale: [%f, %f]", pos.x, pos.y, size.x, size.y, has_alpha, mode, angle, scale.x, scale.y);
|
||||
|
||||
byte *buf = (byte *)temp_buffer(size.x * size.y * 4);
|
||||
|
||||
byte *buf_ptr = buf;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
data->decode_line(i, buf_ptr);
|
||||
buf_ptr += size.x * 4;
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
uint32 *p = (uint32 *)buf;
|
||||
buf_ptr = buf + 3;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
for (int j = 0; j < size.x; j++) {
|
||||
if (!*p++)
|
||||
*buf_ptr = 255;
|
||||
|
||||
buf_ptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putSpr_rot(pos, size, buf, true, mode, angle, scale);
|
||||
}
|
||||
|
||||
void grDispatcher::putSprMask_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_rot([%d, %d], [%d, %d], alpha: %d, mask: %d, mask_alpha: %d, mode: %d, angle: %f", pos.x, pos.y, size.x, size.y, has_alpha, mask_color, mask_alpha, mode, angle);
|
||||
|
||||
byte *buf = (byte *)temp_buffer(size.x * size.y * 4);
|
||||
|
||||
byte *buf_ptr = buf;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
data->decode_line(i, buf_ptr);
|
||||
buf_ptr += size.x * 4;
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
uint32 *p = (uint32 *)buf;
|
||||
buf_ptr = buf + 3;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
for (int j = 0; j < size.x; j++) {
|
||||
if (!*p++)
|
||||
*buf_ptr = 255;
|
||||
|
||||
buf_ptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putSprMask_rot(pos, size, buf, true, mask_color, mask_alpha, mode, angle);
|
||||
}
|
||||
|
||||
void grDispatcher::putSprMask_rle_rot(const Vect2i &pos, const Vect2i &size, const RLEBuffer *data, bool has_alpha, uint32 mask_color, int mask_alpha, int mode, float angle, const Vect2f &scale) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_rot([%d, %d], [%d, %d], alpha: %d, mask: %d, mask_alpha: %d, mode: %d, angle: %f, scale: [%f, %f]", pos.x, pos.y, size.x, size.y, has_alpha, mask_color, mask_alpha, mode, angle, scale.x, scale.y);
|
||||
|
||||
byte *buf = (byte *)temp_buffer(size.x * size.y * 4);
|
||||
|
||||
byte *buf_ptr = buf;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
data->decode_line(i, buf_ptr);
|
||||
buf_ptr += size.x * 4;
|
||||
}
|
||||
|
||||
if (!has_alpha) {
|
||||
uint32 *p = (uint32 *)buf;
|
||||
buf_ptr = buf + 3;
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
for (int j = 0; j < size.x; j++) {
|
||||
if (!*p++)
|
||||
*buf_ptr = 255;
|
||||
|
||||
buf_ptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putSprMask_rot(pos, size, buf, true, mask_color, mask_alpha, mode, angle, scale);
|
||||
}
|
||||
|
||||
inline bool rle_alpha_b(uint32 pixel) {
|
||||
return (reinterpret_cast<byte *>(&pixel)[3] < 200);
|
||||
}
|
||||
inline bool rle_alpha_b16(uint16 pixel) {
|
||||
return pixel < 200;
|
||||
}
|
||||
|
||||
void grDispatcher::drawSprContour(int x, int y, int sx, int sy, const class RLEBuffer *p, int contour_color, int mode, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::drawSprContour([%d, %d], [%d, %d], contour_color: %d, mode: %d, alpha_flag: %d)", x, y, sx, sy, contour_color, mode, alpha_flag);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
int dx = -1;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += (psx - 1) * 2;
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
const uint16 *data0 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(0));
|
||||
const uint16 *data1 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(1));
|
||||
|
||||
px <<= 1;
|
||||
psx <<= 1;
|
||||
|
||||
warning("STUB: grDispatcher::drawSprContour");
|
||||
for (int i = 0; i < psy; i++) {
|
||||
uint16 *scr_buf = (uint16 *)_screenBuf->getBasePtr(x, y);
|
||||
uint16 *scr_buf_prev = (i) ? (uint16 *)_screenBuf->getBasePtr(x, y - dy) : scr_buf;
|
||||
p->decode_line(py + i, i & 1);
|
||||
|
||||
const uint16 *data_ptr = (i & 1) ? data1 + px : data0 + px;
|
||||
const uint16 *data_ptr_prev = (i & 1) ? data0 + px : data1 + px;
|
||||
|
||||
if (!alpha_flag) {
|
||||
uint32 pixel = 0;
|
||||
for (int j = 0; j < psx; j += 2) {
|
||||
pixel = data_ptr[j];
|
||||
|
||||
if (!pixel && j && data_ptr[j - 2]) {
|
||||
*(scr_buf - dx) = contour_color;
|
||||
}
|
||||
if ((pixel && (!j || !data_ptr[j - 2]))) {
|
||||
*scr_buf = contour_color;
|
||||
} else {
|
||||
if (pixel && (!i || !data_ptr_prev[j])) {
|
||||
*scr_buf = contour_color;
|
||||
}
|
||||
}
|
||||
if (!pixel && i && data_ptr_prev[j]) {
|
||||
*scr_buf_prev = contour_color;
|
||||
}
|
||||
|
||||
scr_buf += dx;
|
||||
scr_buf_prev += dx;
|
||||
}
|
||||
if (pixel) *(scr_buf - dx) = contour_color;
|
||||
} else {
|
||||
bool pixel = false;
|
||||
for (int j = 0; j < psx; j += 2) {
|
||||
pixel = rle_alpha_b16(data_ptr[j + 1]);
|
||||
|
||||
if (!pixel && j && rle_alpha_b16(data_ptr[j - 1])) {
|
||||
*(scr_buf - dx) = contour_color;
|
||||
}
|
||||
if ((pixel && (!j || !rle_alpha_b16(data_ptr[j - 1])))) {
|
||||
*scr_buf = contour_color;
|
||||
} else {
|
||||
if (pixel && (!i || !rle_alpha_b16(data_ptr_prev[j + 1]))) {
|
||||
*scr_buf = contour_color;
|
||||
}
|
||||
}
|
||||
if (!pixel && i && rle_alpha_b16(data_ptr_prev[j + 1])) {
|
||||
*scr_buf_prev = contour_color;
|
||||
}
|
||||
|
||||
scr_buf += dx;
|
||||
scr_buf_prev += dx;
|
||||
}
|
||||
if (pixel) *(scr_buf - dx) = contour_color;
|
||||
}
|
||||
|
||||
y += dy;
|
||||
}
|
||||
uint16 *scr_buf_prev = (uint16 *)_screenBuf->getBasePtr(x, y - dy);
|
||||
const uint16 *data_ptr_prev = (psy & 1) ? data0 + px : data1 + px;
|
||||
if (!alpha_flag) {
|
||||
for (int j = 0; j < psx; j += 2) {
|
||||
if (data_ptr_prev[j])
|
||||
*scr_buf_prev = contour_color;
|
||||
scr_buf_prev += dx;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < psx; j += 2) {
|
||||
if (rle_alpha_b16(data_ptr_prev[j + 1]))
|
||||
*scr_buf_prev = contour_color;
|
||||
scr_buf_prev += dx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void grDispatcher::drawSprContour(int x, int y, int sx, int sy, const class RLEBuffer *p, int contour_color, int mode, float scale, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::drawSprContour([%d, %d], [%d, %d], contour_color: %d, mode: %d, scale: %f, alpha_flag: %d)", x, y, sx, sy, contour_color, mode, scale, alpha_flag);
|
||||
|
||||
int sx_dest = round(float(sx) * scale);
|
||||
int sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (!sx_dest || !sy_dest) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
|
||||
if (!alpha_flag) {
|
||||
const uint16 *line0 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(0));
|
||||
const uint16 *line1 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(1));
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16, i & 1);
|
||||
const uint16 *line_src = (i & 1) ? line1 : line0;
|
||||
const uint16 *line_src_prev = (i & 1) ? line0 : line1;
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
uint32 cl = 0;
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
cl = line_src[(fx >> 16) << 1];
|
||||
if (!cl && j != x0 && line_src[((fx - dx) >> 16) << 1])
|
||||
setPixel(x + j - ix, y + i, contour_color);
|
||||
|
||||
if (cl && (j == x0 || !line_src[((fx - dx) >> 16) << 1])) {
|
||||
setPixelFast(x + j, y + i, contour_color);
|
||||
} else {
|
||||
if (cl && (i == y0 || !line_src_prev[(fx >> 16) << 1]))
|
||||
setPixelFast(x + j, y + i, contour_color);
|
||||
}
|
||||
|
||||
if (!cl && i != y0 && line_src_prev[(fx >> 16) << 1])
|
||||
setPixel(x + j, y + i - iy, contour_color);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
if (cl) setPixel(x + x1 - ix, y + i, contour_color);
|
||||
}
|
||||
fx = (1 << 15);
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
const uint16 *line_src_prev = (y1 & 1) ? line0 : line1;
|
||||
if (line_src_prev[(fx >> 16) << 1])
|
||||
setPixel(x + j, y + y1 - iy, contour_color);
|
||||
fx += dx;
|
||||
}
|
||||
} else {
|
||||
const uint16 *line0 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(0));
|
||||
const uint16 *line1 = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(1));
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16, i & 1);
|
||||
const uint16 *line_src = (i & 1) ? line1 : line0;
|
||||
const uint16 *line_src_prev = (i & 1) ? line0 : line1;
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
bool cl = false;
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (clipCheck(x + j, y + i)) {
|
||||
cl = rle_alpha_b16(line_src[((fx >> 16) << 1) + 1]);
|
||||
if (!cl && j != x0 && rle_alpha_b16(line_src[(((fx - dx) >> 16) << 1) + 1]))
|
||||
setPixel(x + j - ix, y + i, contour_color);
|
||||
|
||||
if (cl && (j == x0 || !rle_alpha_b16(line_src[(((fx - dx) >> 16) << 1) + 1]))) {
|
||||
setPixelFast(x + j, y + i, contour_color);
|
||||
} else {
|
||||
if (cl && (i == y0 || !rle_alpha_b16(line_src_prev[((fx >> 16) << 1) + 1])))
|
||||
setPixelFast(x + j, y + i, contour_color);
|
||||
}
|
||||
|
||||
if (!cl && i != y0 && rle_alpha_b16(line_src_prev[((fx >> 16) << 1) + 1]))
|
||||
setPixel(x + j, y + i - iy, contour_color);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
if (cl) setPixel(x + x1 - ix, y + i, contour_color);
|
||||
}
|
||||
fx = (1 << 15);
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
const uint16 *line_src_prev = (y1 & 1) ? line0 : line1;
|
||||
if (rle_alpha_b16(line_src_prev[((fx >> 16) << 1) + 1]))
|
||||
setPixel(x + j, y + y1 - iy, contour_color);
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
597
engines/qdengine/system/graphics/gr_draw_sprite_rle_z.cpp
Normal file
597
engines/qdengine/system/graphics/gr_draw_sprite_rle_z.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/rle_compress.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
void grDispatcher::putSpr_rle_z(int x, int y, int z, int sx, int sy, const class RLEBuffer *p, int mode, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_z([%d, %d], [%d, %d], mode: %d, alpha: %d", x, y, sx, sy, mode, alpha_flag);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
|
||||
if (bytes_per_pixel() == 4) {
|
||||
int dx = -4;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x3 = x * 4;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x3 += (psx - 1) * 4;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 4;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
psx += px;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x3);
|
||||
zbuf_t *z_buf = zbuffer_ + SizeX * y + x;
|
||||
|
||||
const int8 *rle_header = p->header_ptr(py + i);
|
||||
const uint32 *rle_data = p->data_ptr(py + i);
|
||||
|
||||
int j = 0;
|
||||
int8 count = 0;
|
||||
while (j < px) {
|
||||
count = *rle_header++;
|
||||
if (count > 0) {
|
||||
if (count + j <= px) {
|
||||
j += count;
|
||||
rle_data++;
|
||||
count = 0;
|
||||
} else {
|
||||
count -= px - j;
|
||||
j = px;
|
||||
}
|
||||
} else {
|
||||
if (j - count <= px) {
|
||||
j -= count;
|
||||
rle_data -= count;
|
||||
count = 0;
|
||||
} else {
|
||||
count += px - j;
|
||||
rle_data += px - j;
|
||||
j = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alpha_flag) {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
*reinterpret_cast<uint32 *>(scr_buf) = *rle_data;
|
||||
*z_buf = z;
|
||||
}
|
||||
z_buf += zdx;
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
*reinterpret_cast<uint32 *>(scr_buf) = *rle_data++;
|
||||
*z_buf = z;
|
||||
}
|
||||
z_buf += zdx;
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
} else {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const byte *>(rle_data)[3];
|
||||
if (a != 255) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2] + ((a * scr_buf[2]) >> 8);
|
||||
*z_buf = z;
|
||||
}
|
||||
z_buf += zdx;
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const byte *>(rle_data)[3];
|
||||
if (a != 255) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2] + ((a * scr_buf[2]) >> 8);
|
||||
*z_buf = z;
|
||||
}
|
||||
rle_data++;
|
||||
z_buf += zdx;
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 3) {
|
||||
int dx = -3;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x3 = x * 3;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x3 += psx * 3 - 3;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 3;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
psx += px;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x3);
|
||||
zbuf_t *z_buf = zbuffer_ + SizeX * y + x;
|
||||
|
||||
const int8 *rle_header = p->header_ptr(py + i);
|
||||
const uint32 *rle_data = p->data_ptr(py + i);
|
||||
|
||||
int j = 0;
|
||||
int8 count = 0;
|
||||
while (j < px) {
|
||||
count = *rle_header++;
|
||||
if (count > 0) {
|
||||
if (count + j <= px) {
|
||||
j += count;
|
||||
rle_data++;
|
||||
count = 0;
|
||||
} else {
|
||||
count -= px - j;
|
||||
j = px;
|
||||
}
|
||||
} else {
|
||||
if (j - count <= px) {
|
||||
j -= count;
|
||||
rle_data -= count;
|
||||
count = 0;
|
||||
} else {
|
||||
count += px - j;
|
||||
rle_data += px - j;
|
||||
j = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alpha_flag) {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0];
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1];
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2];
|
||||
*z_buf = z;
|
||||
}
|
||||
z_buf += zdx;
|
||||
scr_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0];
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1];
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2];
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += zdx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
} else {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const byte *>(rle_data)[3];
|
||||
if (a != 255) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2] + ((a * scr_buf[2]) >> 8);
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += zdx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const byte *>(rle_data)[3];
|
||||
if (a != 255) {
|
||||
scr_buf[0] = reinterpret_cast<const byte *>(rle_data)[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = reinterpret_cast<const byte *>(rle_data)[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = reinterpret_cast<const byte *>(rle_data)[2] + ((a * scr_buf[2]) >> 8);
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += zdx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 2) {
|
||||
int dx = -1;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += (psx - 1) * 2;
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 1;
|
||||
|
||||
psx += px;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
uint16 *scr_buf = reinterpret_cast<uint16 *>(screenBuf + yTable[y] + x * 2);
|
||||
zbuf_t *z_buf = zbuffer_ + y * SizeX + x;
|
||||
|
||||
const int8 *rle_header = p->header_ptr(py + i);
|
||||
const uint32 *rle_data = p->data_ptr(py + i);
|
||||
|
||||
int j = 0;
|
||||
int8 count = 0;
|
||||
while (j < px) {
|
||||
count = *rle_header++;
|
||||
if (count > 0) {
|
||||
if (count + j <= px) {
|
||||
j += count;
|
||||
rle_data++;
|
||||
count = 0;
|
||||
} else {
|
||||
count -= px - j;
|
||||
j = px;
|
||||
}
|
||||
} else {
|
||||
if (j - count <= px) {
|
||||
j -= count;
|
||||
rle_data -= count;
|
||||
count = 0;
|
||||
} else {
|
||||
count += px - j;
|
||||
rle_data += px - j;
|
||||
j = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alpha_flag) {
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
*scr_buf = reinterpret_cast<const uint16 *>(rle_data)[0];
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
if (*rle_data) {
|
||||
*scr_buf = reinterpret_cast<const uint16 *>(rle_data)[0];
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
} else {
|
||||
const uint32 mask_r = (pixel_format_ == GR_RGB565) ? mask_565_r : mask_555_r;
|
||||
const uint32 mask_g = (pixel_format_ == GR_RGB565) ? mask_565_g : mask_555_g;
|
||||
const uint32 mask_b = (pixel_format_ == GR_RGB565) ? mask_565_b : mask_555_b;
|
||||
|
||||
while (j < psx) {
|
||||
if (count > 0) {
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const uint16 *>(rle_data)[1];
|
||||
if (a != 255) {
|
||||
uint32 sc = *scr_buf;
|
||||
*scr_buf = reinterpret_cast<const uint16 *>(rle_data)[0] +
|
||||
(((((sc & mask_r) * a) >> 8) & mask_r) |
|
||||
((((sc & mask_g) * a) >> 8) & mask_g) |
|
||||
((((sc & mask_b) * a) >> 8) & mask_b));
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += dx;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
rle_data++;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
count = -count;
|
||||
while (count && j < psx) {
|
||||
uint32 a = reinterpret_cast<const uint16 *>(rle_data)[1];
|
||||
if (a != 255) {
|
||||
uint32 sc = *scr_buf;
|
||||
*scr_buf = reinterpret_cast<const uint16 *>(rle_data)[0] +
|
||||
(((((sc & mask_r) * a) >> 8) & mask_r) |
|
||||
((((sc & mask_g) * a) >> 8) & mask_g) |
|
||||
((((sc & mask_b) * a) >> 8) & mask_b));
|
||||
*z_buf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
z_buf += dx;
|
||||
rle_data++;
|
||||
count--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count = *rle_header++;
|
||||
}
|
||||
}
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_rle_z(int x, int y, int z, int sx, int sy, const class RLEBuffer *p, int mode, float scale, bool alpha_flag) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_rle_z([%d, %d], [%d, %d], mode: %d, scale: %f, alpha: %d", x, y, sx, sy, mode, scale, alpha_flag);
|
||||
|
||||
int sx_dest = round(float(sx) * scale);
|
||||
int sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (!sx_dest || !sy_dest) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 2) {
|
||||
if (!alpha_flag) {
|
||||
const uint16 *line_src = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(0));
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (ClipCheck(x + j, y + i)) {
|
||||
uint32 cl = line_src[(fx >> 16) << 1];
|
||||
if (cl) {
|
||||
setPixelFast(x + j, y + i, cl);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const uint16 *line_src = reinterpret_cast<const uint16 *>(RLEBuffer::get_buffer(0));
|
||||
|
||||
const uint32 mask_r = (pixel_format_ == GR_RGB565) ? mask_565_r : mask_555_r;
|
||||
const uint32 mask_g = (pixel_format_ == GR_RGB565) ? mask_565_g : mask_555_g;
|
||||
const uint32 mask_b = (pixel_format_ == GR_RGB565) ? mask_565_b : mask_555_b;
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (ClipCheck(x + j, y + i)) {
|
||||
uint32 a = line_src[((fx >> 16) << 1) + 1];
|
||||
if (a != 255) {
|
||||
uint32 cl = line_src[(fx >> 16) << 1];
|
||||
|
||||
uint32 scl;
|
||||
getPixel(x + j, y + i, scl);
|
||||
|
||||
scl = cl +
|
||||
(((((scl & mask_r) * a) >> 8) & mask_r) |
|
||||
((((scl & mask_g) * a) >> 8) & mask_g) |
|
||||
((((scl & mask_b) * a) >> 8) & mask_b));
|
||||
|
||||
setPixelFast(x + j, y + i, scl);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 3 || bytes_per_pixel() == 4) {
|
||||
int sx3 = sx * 3;
|
||||
const byte *line_src = RLEBuffer::get_buffer(0);
|
||||
|
||||
if (!alpha_flag) {
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (ClipCheck(x + j, y + i)) {
|
||||
int idx = (fx >> 16) << 2;
|
||||
|
||||
uint32 r = line_src[idx + 2];
|
||||
uint32 g = line_src[idx + 1];
|
||||
uint32 b = line_src[idx + 0];
|
||||
|
||||
if (r || g || b) {
|
||||
setPixelFast(x + j, y + i, r, g, b);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
p->decode_line(fy >> 16);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
if (ClipCheck(x + j, y + i)) {
|
||||
int idx = (fx >> 16) << 2;
|
||||
|
||||
uint32 a = line_src[idx + 3];
|
||||
if (a != 255) {
|
||||
uint32 sr, sg, sb;
|
||||
getPixel(x + j, y + i, sr, sg, sb);
|
||||
|
||||
uint32 r = line_src[idx + 2] + ((a * sr) >> 8);
|
||||
uint32 g = line_src[idx + 1] + ((a * sg) >> 8);
|
||||
uint32 b = line_src[idx + 0] + ((a * sb) >> 8);
|
||||
|
||||
setPixelFast(x + j, y + i, r, g, b);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
}
|
||||
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace QDEngine
|
||||
573
engines/qdengine/system/graphics/gr_draw_sprite_z.cpp
Normal file
573
engines/qdengine/system/graphics/gr_draw_sprite_z.cpp
Normal file
@@ -0,0 +1,573 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
#ifdef _GR_ENABLE_ZBUFFER
|
||||
void grDispatcher::putSpr_a_z(int x, int y, int z, int sx, int sy, const byte *p, int mode, float scale) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::a_z([%d, %d], [%d, %d], mode: %d, scale: %f)", pos.x, pos.y, size.x, size.y, mode, scale);
|
||||
|
||||
int i, j, sx_dest, sy_dest;
|
||||
|
||||
sx_dest = round(float(sx) * scale);
|
||||
sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (!sx_dest || !sy_dest) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 2) {
|
||||
const uint16 *src = reinterpret_cast<const uint16 *>(p);
|
||||
sx <<= 1;
|
||||
if (pixel_format_ == GR_ARGB1555) {
|
||||
for (i = y0; i != y1; i += iy) {
|
||||
const uint16 *line_src = src + ((fy >> 16) * sx);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (j = x0; j != x1; j += ix) {
|
||||
uint32 a = line_src[((fx >> 16) << 1) + 1];
|
||||
if (a != 255 && ClipCheck(x + j, y + i)) {
|
||||
uint32 sc;
|
||||
getPixel(x + j, y + i, sc);
|
||||
setPixel(x + j, y + i, alpha_blend_555(line_src[(fx >> 16) << 1], sc, a));
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = y0; i != y1; i += iy) {
|
||||
const uint16 *line_src = src + ((fy >> 16) * sx);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (j = x0; j != x1; j += ix) {
|
||||
uint32 a = line_src[((fx >> 16) << 1) + 1];
|
||||
if (a != 255 && ClipCheck(x + j, y + i)) {
|
||||
uint32 sc;
|
||||
getPixel(x + j, y + i, sc);
|
||||
setPixel(x + j, y + i, alpha_blend_565(line_src[(fx >> 16) << 1], sc, a));
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 3 || bytes_per_pixel() == 4) {
|
||||
int sx3 = sx * 4;
|
||||
|
||||
for (i = y0; i != y1; i += iy) {
|
||||
const byte *line_src = p + ((fy >> 16) * sx3);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (j = x0; j != x1; j += ix) {
|
||||
int idx = (fx >> 16) << 2;
|
||||
uint32 a = line_src[idx + 3];
|
||||
if (a != 255 && ClipCheck(x + j, y + i)) {
|
||||
uint32 sr, sg, sb;
|
||||
getPixel(x + j, y + i, sr, sg, sb);
|
||||
|
||||
uint32 r = line_src[idx + 2] + ((a * sr) >> 8);
|
||||
uint32 g = line_src[idx + 1] + ((a * sg) >> 8);
|
||||
uint32 b = line_src[idx + 0] + ((a * sb) >> 8);
|
||||
|
||||
setPixel(x + j, y + i, r, g, b);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_z(int x, int y, int z, int sx, int sy, const byte *p, int mode, float scale) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_z([%d, %d], [%d, %d], mode: %d, scale: %f)", pos.x, pos.y, size.x, size.y, mode, scale);
|
||||
|
||||
int sx_dest = round(float(sx) * scale);
|
||||
int sy_dest = round(float(sy) * scale);
|
||||
|
||||
if (!sx_dest || !sy_dest) return;
|
||||
|
||||
int dx = (sx << 16) / sx_dest;
|
||||
int dy = (sy << 16) / sy_dest;
|
||||
int fx = (1 << 15);
|
||||
int fy = (1 << 15);
|
||||
|
||||
int x0 = 0;
|
||||
int x1 = sx_dest;
|
||||
int ix = 1;
|
||||
|
||||
int y0 = 0;
|
||||
int y1 = sy_dest;
|
||||
int iy = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y0 = sy_dest,
|
||||
y1 = 0;
|
||||
iy = -1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x0 = sx_dest,
|
||||
x1 = 0;
|
||||
ix = -1;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 2) {
|
||||
const uint16 *src = reinterpret_cast<const uint16 *>(p);
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
const uint16 *line_src = src + ((fy >> 16) * sx);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
uint32 cl = line_src[fx >> 16];
|
||||
if (cl) {
|
||||
setPixel(x + j, y + i, cl);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 3) {
|
||||
int sx3 = sx * 3;
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
const byte *line_src = p + ((fy >> 16) * sx3);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
int idx = (fx >> 16) * 3;
|
||||
|
||||
uint32 r = line_src[idx + 2];
|
||||
uint32 g = line_src[idx + 1];
|
||||
uint32 b = line_src[idx + 0];
|
||||
|
||||
if (r || g || b) {
|
||||
setPixel(x + j, y + i, r, g, b);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel() == 4) {
|
||||
const uint32 *src = reinterpret_cast<const uint32 *>(p);
|
||||
|
||||
for (int i = y0; i != y1; i += iy) {
|
||||
const uint32 *line_src = src + ((fy >> 16) * sx);
|
||||
|
||||
fy += dy;
|
||||
fx = (1 << 15);
|
||||
|
||||
for (int j = x0; j != x1; j += ix) {
|
||||
uint32 cl = line_src[fx >> 16];
|
||||
if (cl) {
|
||||
setPixel(x + j, y + i, cl);
|
||||
put_z(x + j, y + i, z);
|
||||
}
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_a_z(int x, int y, int z, int sx, int sy, const byte *p, int mode) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_a_z([%d, %d], [%d, %d], mode: %d)", pos.x, pos.y, size.x, size.y, mode);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
|
||||
if (bytes_per_pixel() == 4) {
|
||||
int dx = -4;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x4 = x * 4;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x4 += (psx - 1) * 4;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 4;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
int px3 = px * 4;
|
||||
int sx3 = sx * 4;
|
||||
|
||||
const byte *data_ptr = p + py * sx3;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x4);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + x;
|
||||
const byte *data_line = data_ptr + px3;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
uint32 a = data_line[3];
|
||||
if (a != 255) {
|
||||
if (a) {
|
||||
scr_buf[0] = data_line[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = data_line[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = data_line[2] + ((a * scr_buf[2]) >> 8);
|
||||
} else {
|
||||
scr_buf[0] = data_line[0];
|
||||
scr_buf[1] = data_line[1];
|
||||
scr_buf[2] = data_line[2];
|
||||
}
|
||||
*zbuf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
zbuf += zdx;
|
||||
data_line += 4;
|
||||
}
|
||||
data_ptr += sx3;
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 3) {
|
||||
int dx = -3;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x3 = x * 3;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x3 += (psx - 1) * 3;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 3;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
int px3 = px * 4;
|
||||
int sx3 = sx * 4;
|
||||
|
||||
const byte *data_ptr = p + py * sx3;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x3);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + x;
|
||||
const byte *data_line = data_ptr + px3;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
uint32 a = data_line[3];
|
||||
if (a != 255) {
|
||||
if (a) {
|
||||
scr_buf[0] = data_line[0] + ((a * scr_buf[0]) >> 8);
|
||||
scr_buf[1] = data_line[1] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = data_line[2] + ((a * scr_buf[2]) >> 8);
|
||||
} else {
|
||||
scr_buf[0] = data_line[0];
|
||||
scr_buf[1] = data_line[1];
|
||||
scr_buf[2] = data_line[2];
|
||||
}
|
||||
*zbuf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
zbuf += zdx;
|
||||
data_line += 4;
|
||||
}
|
||||
data_ptr += sx3;
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 2) {
|
||||
int dx = -1;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
x <<= 1;
|
||||
sx <<= 1;
|
||||
px <<= 1;
|
||||
|
||||
const uint16 *data_ptr = reinterpret_cast<const uint16 *>(p) + py * sx;
|
||||
|
||||
if (pixel_format_ == GR_RGB565) {
|
||||
for (int i = 0; i < psy; i++) {
|
||||
uint16 *scr_buf = reinterpret_cast<uint16 *>(screenBuf + yTable[y] + x);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + (x >> 1);
|
||||
const uint16 *data_line = data_ptr + px;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
uint32 a = data_line[1];
|
||||
*scr_buf = alpha_blend_565(*data_line, *scr_buf, a);
|
||||
if (a != 255) *zbuf = z;
|
||||
scr_buf += dx;
|
||||
zbuf += dx;
|
||||
data_line += 2;
|
||||
}
|
||||
data_ptr += sx;
|
||||
y += dy;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < psy; i++) {
|
||||
uint16 *scr_buf = reinterpret_cast<uint16 *>(screenBuf + yTable[y] + x);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + (x >> 1);
|
||||
const uint16 *data_line = data_ptr + px;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
uint32 a = data_line[1];
|
||||
*scr_buf = alpha_blend_555(*data_line, *scr_buf, a);
|
||||
if (a != 255) *zbuf = z;
|
||||
scr_buf += dx;
|
||||
zbuf += dx;
|
||||
data_line += 2;
|
||||
}
|
||||
data_ptr += sx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void grDispatcher::putSpr_z(int x, int y, int z, int sx, int sy, const byte *p, int mode) {
|
||||
debugC(4, kDebugGraphics, "grDispatcher::putSpr_z([%d, %d], [%d, %d], mode: %d", pos.x, pos.y, size.x, size.y, mode);
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = sx;
|
||||
int psy = sy;
|
||||
|
||||
if (!clip_rectangle(x, y, px, py, psx, psy)) return;
|
||||
|
||||
if (bytes_per_pixel() == 4) {
|
||||
int dx = -4;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x4 = x * 4;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x4 += psx * 4 - 4;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 4;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
int px3 = px * 3;
|
||||
int sx3 = sx * 3;
|
||||
|
||||
const byte *data_ptr = p + py * sx3;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x4);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + x;
|
||||
const byte *data_line = data_ptr + px3;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
if (data_line[0] || data_line[1] || data_line[2]) {
|
||||
scr_buf[0] = data_line[0];
|
||||
scr_buf[1] = data_line[1];
|
||||
scr_buf[2] = data_line[2];
|
||||
*zbuf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
zbuf += zdx;
|
||||
data_line += 3;
|
||||
}
|
||||
|
||||
data_ptr += sx3;
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 3) {
|
||||
int dx = -3;
|
||||
int zdx = -1;
|
||||
int dy = -1;
|
||||
|
||||
int x3 = x * 3;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x3 += psx * 3 - 3;
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else {
|
||||
dx = 3;
|
||||
zdx = 1;
|
||||
}
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
int px3 = px * 3;
|
||||
int sx3 = sx * 3;
|
||||
|
||||
const byte *data_ptr = p + py * sx3;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(screenBuf + yTable[y] + x3);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + x;
|
||||
const byte *data_line = data_ptr + px3;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
if (data_line[0] || data_line[1] || data_line[2]) {
|
||||
scr_buf[0] = data_line[0];
|
||||
scr_buf[1] = data_line[1];
|
||||
scr_buf[2] = data_line[2];
|
||||
*zbuf = z;
|
||||
}
|
||||
scr_buf += dx;
|
||||
zbuf += zdx;
|
||||
data_line += 3;
|
||||
}
|
||||
|
||||
data_ptr += sx3;
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bytes_per_pixel() == 2) {
|
||||
int dx = -1;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += psx - 1;
|
||||
px = sx - px - psx;
|
||||
} else
|
||||
dx = 1;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = sy - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
x <<= 1;
|
||||
|
||||
const uint16 *data_ptr = reinterpret_cast<const uint16 *>(p) + py * sx;
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
uint16 *scr_buf = reinterpret_cast<uint16 *>(screenBuf + yTable[y] + x);
|
||||
zbuf_t *zbuf = zbuffer_ + y * SizeX + x;
|
||||
const uint16 *data_line = data_ptr + px;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
if (*data_line) {
|
||||
*scr_buf = *data_line;
|
||||
*zbuf = z;
|
||||
}
|
||||
zbuf += dx;
|
||||
scr_buf += dx;
|
||||
data_line++;
|
||||
}
|
||||
|
||||
data_ptr += sx;
|
||||
y += dy;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace QDEngine
|
||||
129
engines/qdengine/system/graphics/gr_font.cpp
Normal file
129
engines/qdengine/system/graphics/gr_font.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/gr_font.h"
|
||||
#include "qdengine/qdcore/qd_file_manager.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
grFont::grFont() : _alpha_buffer(NULL) {
|
||||
_size_x = _size_y = 0;
|
||||
_alpha_buffer_sx = _alpha_buffer_sy = 0;
|
||||
|
||||
_chars.reserve(256);
|
||||
}
|
||||
|
||||
grFont::~grFont() {
|
||||
delete[] _alpha_buffer;
|
||||
}
|
||||
|
||||
bool grFont::load(const Common::Path &fname) {
|
||||
Common::String str(fname.toString());
|
||||
str += ".tga";
|
||||
|
||||
Common::File file;
|
||||
file.open(Common::Path(str));
|
||||
|
||||
if (load_alpha(&file)) {
|
||||
str = fname.toString();
|
||||
str += ".idx";
|
||||
|
||||
file.open(Common::Path(str));
|
||||
if (load_index(&file))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool grFont::load_index(Common::SeekableReadStream *fh) {
|
||||
Common::String buf = fh->readString();
|
||||
char *pos = buf.begin();
|
||||
|
||||
int num_ch, sx, sy;
|
||||
|
||||
sx = strtol(pos, &pos, 0);
|
||||
sy = strtol(pos, &pos, 0);
|
||||
num_ch = strtol(pos, &pos, 0);
|
||||
|
||||
grFontChar chr;
|
||||
for (int i = 0; i < num_ch; i++) {
|
||||
int x, y;
|
||||
|
||||
chr._code = strtol(pos, &pos, 0);
|
||||
x = strtol(pos, &pos, 0);
|
||||
y = strtol(pos, &pos, 0);
|
||||
sx = strtol(pos, &pos, 0);
|
||||
sy = strtol(pos, &pos, 0);
|
||||
|
||||
chr._region = grScreenRegion(x, y, sx, sy);
|
||||
_chars.push_back(chr);
|
||||
|
||||
if (sx > _size_x) _size_x = sx;
|
||||
if (sy > _size_y) _size_y = sy;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool grFont::load_alpha(Common::SeekableReadStream *fh) {
|
||||
byte header[18];
|
||||
fh->read(header, 18);
|
||||
|
||||
if (header[0])
|
||||
return false;
|
||||
|
||||
if (header[1])
|
||||
return false;
|
||||
|
||||
if (header[2] != 2 && header[2] != 3)
|
||||
return false;
|
||||
|
||||
int sx = _alpha_buffer_sx = header[12] + (header[13] << 8);
|
||||
int sy = _alpha_buffer_sy = header[14] + (header[15] << 8);
|
||||
|
||||
int colors = header[16];
|
||||
int flags = header[17];
|
||||
|
||||
int ssx = sx * colors / 8;
|
||||
|
||||
_alpha_buffer = new byte[ssx * sy];
|
||||
|
||||
if (!(flags & 0x20)) {
|
||||
int idx = (sy - 1) * ssx;
|
||||
for (int i = 0; i < sy; i++) {
|
||||
fh->read(_alpha_buffer + idx, ssx);
|
||||
idx -= ssx;
|
||||
}
|
||||
} else
|
||||
fh->read(_alpha_buffer, ssx * sy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
99
engines/qdengine/system/graphics/gr_font.h
Normal file
99
engines/qdengine/system/graphics/gr_font.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_GR_FONT_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_GR_FONT_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class grFont {
|
||||
public:
|
||||
grFont();
|
||||
~grFont();
|
||||
|
||||
bool load(const Common::Path &fname);
|
||||
|
||||
bool load_index(Common::SeekableReadStream *fh);
|
||||
bool load_alpha(Common::SeekableReadStream *fh);
|
||||
|
||||
int size_x() const {
|
||||
return _size_x;
|
||||
}
|
||||
int size_y() const {
|
||||
return _size_y;
|
||||
}
|
||||
|
||||
int alpha_buffer_size_x() const {
|
||||
return _alpha_buffer_sx;
|
||||
}
|
||||
int alpha_buffer_size_y() const {
|
||||
return _alpha_buffer_sy;
|
||||
}
|
||||
|
||||
const byte *alpha_buffer() const {
|
||||
return _alpha_buffer;
|
||||
}
|
||||
|
||||
const grScreenRegion find_char(int code) const {
|
||||
grFontCharVector::const_iterator it = Common::find(_chars.begin(), _chars.end(), code);
|
||||
if (it != _chars.end()) return it->_region;
|
||||
|
||||
return grScreenRegion_EMPTY;
|
||||
}
|
||||
|
||||
int char_width(int code) const {
|
||||
return code == ' ' ? size_x() / 2 : find_char(code).size_x();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int _size_x;
|
||||
int _size_y;
|
||||
|
||||
int _alpha_buffer_sx;
|
||||
int _alpha_buffer_sy;
|
||||
byte *_alpha_buffer;
|
||||
|
||||
struct grFontChar {
|
||||
grFontChar() : _code(-1) { }
|
||||
|
||||
int _code;
|
||||
grScreenRegion _region;
|
||||
|
||||
bool operator == (int code) const {
|
||||
return (_code == code);
|
||||
}
|
||||
};
|
||||
|
||||
typedef Std::vector<grFontChar> grFontCharVector;
|
||||
grFontCharVector _chars;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_GR_FONT_H
|
||||
139
engines/qdengine/system/graphics/gr_screen_region.h
Normal file
139
engines/qdengine/system/graphics/gr_screen_region.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_GR_SCREEN_REGION_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_GR_SCREEN_REGION_H
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
#define grScreenRegion_EMPTY grScreenRegion(0, 0, 0, 0)
|
||||
|
||||
//! Прямоугольная область на экране.
|
||||
class grScreenRegion {
|
||||
public:
|
||||
grScreenRegion() : _x(0), _y(0), _size_x(0), _size_y(0) {}
|
||||
grScreenRegion(int x, int y, int sx, int sy) : _x(x), _y(y), _size_x(sx), _size_y(sy) {}
|
||||
|
||||
bool operator == (const grScreenRegion ®) const {
|
||||
if (_x == reg._x && _y == reg._y && _size_x == reg._size_x && _size_y == reg._size_y)
|
||||
return true;
|
||||
|
||||
if (is_empty() && reg.is_empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator != (const grScreenRegion ®) const {
|
||||
if (is_empty() && reg.is_empty())
|
||||
return false;
|
||||
|
||||
if (_x != reg._x || _y != reg._y || _size_x != reg._size_x || _size_y != reg._size_y)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
grScreenRegion &operator += (const grScreenRegion ®) {
|
||||
if (reg.is_empty()) return *this;
|
||||
|
||||
if (is_empty()) {
|
||||
*this = reg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int x0 = (min_x() < reg.min_x()) ? min_x() : reg.min_x();
|
||||
int x1 = (max_x() > reg.max_x()) ? max_x() : reg.max_x();
|
||||
|
||||
int y0 = (min_y() < reg.min_y()) ? min_y() : reg.min_y();
|
||||
int y1 = (max_y() > reg.max_y()) ? max_y() : reg.max_y();
|
||||
|
||||
_x = (x0 + x1) / 2;
|
||||
_y = (y0 + y1) / 2;
|
||||
|
||||
_size_x = x1 - x0;
|
||||
_size_y = y1 - y0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int x() const {
|
||||
return _x;
|
||||
}
|
||||
int y() const {
|
||||
return _y;
|
||||
}
|
||||
|
||||
int size_x() const {
|
||||
return _size_x;
|
||||
}
|
||||
int size_y() const {
|
||||
return _size_y;
|
||||
}
|
||||
|
||||
int min_x() const {
|
||||
return _x - _size_x / 2;
|
||||
}
|
||||
int max_x() const {
|
||||
return _x + _size_x / 2;
|
||||
}
|
||||
|
||||
int min_y() const {
|
||||
return _y - _size_y / 2;
|
||||
}
|
||||
int max_y() const {
|
||||
return _y + _size_y / 2;
|
||||
}
|
||||
|
||||
void move(int dx, int dy) {
|
||||
_x += dx;
|
||||
_y += dy;
|
||||
}
|
||||
|
||||
bool is_empty() const {
|
||||
return (!_size_x || !_size_y);
|
||||
}
|
||||
|
||||
bool is_inside(int x, int y) const {
|
||||
if (x >= min_x() && x < max_x() && y >= min_y() && y < max_y()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_size_x = 0;
|
||||
}
|
||||
|
||||
static const grScreenRegion EMPTY;
|
||||
|
||||
private:
|
||||
|
||||
//! координаты центра области
|
||||
int _x;
|
||||
int _y;
|
||||
|
||||
int _size_x;
|
||||
int _size_y;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_GR_SCREEN_REGION_H
|
||||
705
engines/qdengine/system/graphics/gr_tile_animation.cpp
Normal file
705
engines/qdengine/system/graphics/gr_tile_animation.cpp
Normal file
@@ -0,0 +1,705 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "image/png.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/gr_tile_animation.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
CompressionProgressHandler grTileAnimation::_progressHandler;
|
||||
void *grTileAnimation::_progressHandlerContext;
|
||||
|
||||
grTileAnimation::grTileAnimation() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void grTileAnimation::clear() {
|
||||
_hasAlpha = false;
|
||||
|
||||
_compression = TILE_UNCOMPRESSED;
|
||||
|
||||
_frameCount = 0;
|
||||
_frameSize = Vect2i(0, 0);
|
||||
_frameTileSize = Vect2i(0, 0);
|
||||
|
||||
_frameIndex.clear();
|
||||
FrameIndex(_frameIndex).swap(_frameIndex);
|
||||
|
||||
_tileOffsets.clear();
|
||||
TileOffsets(_tileOffsets).swap(_tileOffsets);
|
||||
|
||||
for (auto &i : _decompressedTiles) {
|
||||
free((void *)i._value.data());
|
||||
}
|
||||
_decompressedTiles.clear();
|
||||
|
||||
_tileData.clear();
|
||||
TileData(_tileData).swap(_tileData);
|
||||
}
|
||||
|
||||
void grTileAnimation::init(int frame_count, const Vect2i &frame_size, bool alpha_flag) {
|
||||
clear();
|
||||
|
||||
_hasAlpha = alpha_flag;
|
||||
|
||||
_frameSize = frame_size;
|
||||
|
||||
_frameTileSize.x = (frame_size.x + GR_TILE_SPRITE_SIZE_X / 2) / GR_TILE_SPRITE_SIZE_X;
|
||||
_frameTileSize.y = (frame_size.y + GR_TILE_SPRITE_SIZE_Y / 2) / GR_TILE_SPRITE_SIZE_Y;
|
||||
|
||||
_frameIndex.reserve(frame_count * _frameTileSize.x * _frameTileSize.y);
|
||||
|
||||
_tileOffsets.reserve(frame_count * _frameTileSize.x * _frameTileSize.y + 1);
|
||||
_tileOffsets.push_back(0);
|
||||
|
||||
_tileData.reserve(frame_count * _frameTileSize.x * _frameTileSize.y * GR_TILE_SPRITE_SIZE);
|
||||
|
||||
_frameCount = frame_count;
|
||||
}
|
||||
|
||||
void grTileAnimation::compact() {
|
||||
TileOffsets(_tileOffsets).swap(_tileOffsets);
|
||||
TileData(_tileData).swap(_tileData);
|
||||
debugC(3, kDebugLog, "Tile animation: %u Kbytes", (_frameIndex.size() + _tileData.size() + _tileOffsets.size()) * 4 / 1024);
|
||||
}
|
||||
|
||||
bool grTileAnimation::compress(grTileCompressionMethod method) {
|
||||
if (_compression != TILE_UNCOMPRESSED)
|
||||
return false;
|
||||
|
||||
_compression = method;
|
||||
|
||||
TileData tile_data;
|
||||
tile_data.reserve(_tileData.size());
|
||||
|
||||
TileOffsets tile_offsets;
|
||||
tile_offsets.reserve(_tileOffsets.size());
|
||||
tile_offsets.push_back(0);
|
||||
|
||||
TileData tile_vector = TileData(GR_TILE_SPRITE_SIZE * 4, 0);
|
||||
|
||||
int count = tileCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_progressHandler) {
|
||||
int percent_done = 100 * (i + 1) / count;
|
||||
(*_progressHandler)(percent_done, _progressHandlerContext);
|
||||
}
|
||||
|
||||
uint32 *data = &*_tileData.begin() + i * GR_TILE_SPRITE_SIZE;
|
||||
|
||||
uint32 offs = tile_offsets.back();
|
||||
uint32 sz = grTileSprite::compress(data, &*tile_vector.begin(), method);
|
||||
|
||||
for (uint32 j = 0; j < sz; j++)
|
||||
tile_data.push_back(tile_vector[j]);
|
||||
|
||||
tile_offsets.push_back(offs + sz);
|
||||
}
|
||||
|
||||
_tileData.swap(tile_data);
|
||||
_tileOffsets.swap(tile_offsets);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
grTileSprite grTileAnimation::getTile(int tile_index) const {
|
||||
debugC(3, kDebugTemp, "The tile index is given by %d", tile_index);
|
||||
static uint32 tile_buf[GR_TILE_SPRITE_SIZE];
|
||||
|
||||
if (_decompressedTiles.contains(tile_index)) {
|
||||
return _decompressedTiles[tile_index];
|
||||
}
|
||||
|
||||
switch (_compression) {
|
||||
case TILE_UNCOMPRESSED:
|
||||
return grTileSprite(&*_tileData.begin() + _tileOffsets[tile_index]);
|
||||
default:
|
||||
if (tile_index >= (int)_tileOffsets.size()) {
|
||||
warning("grTileAnimation::getTile(): Too big tile index %d >= %d", tile_index, _tileOffsets.size());
|
||||
break;
|
||||
}
|
||||
if (_tileOffsets[tile_index] >= _tileData.size()) {
|
||||
warning("grTileAnimation::getTile(): Too big tile offset %d (%d >= %d)", tile_index, _tileOffsets[tile_index], _tileData.size());
|
||||
break;
|
||||
}
|
||||
if (!grTileSprite::uncompress(&*_tileData.begin() + _tileOffsets[tile_index], GR_TILE_SPRITE_SIZE, tile_buf, _compression)) {
|
||||
warning("Unknown compression algorithm");
|
||||
}
|
||||
}
|
||||
|
||||
uint32 *tempBuf = new uint32[GR_TILE_SPRITE_SIZE];
|
||||
memcpy(tempBuf, tile_buf, GR_TILE_SPRITE_SIZE * sizeof(uint32));
|
||||
|
||||
_decompressedTiles[tile_index] = grTileSprite(tempBuf);
|
||||
return _decompressedTiles[tile_index];
|
||||
}
|
||||
|
||||
void grTileAnimation::addFrame(const uint32 *frame_data) {
|
||||
TileData tile_vector = TileData(GR_TILE_SPRITE_SIZE, 0);
|
||||
TileData tile_vector2 = TileData(GR_TILE_SPRITE_SIZE * 4, 0);
|
||||
|
||||
if (_progressHandler) {
|
||||
int percent_done = 100 * (_frameIndex.size() / (_frameTileSize.x * _frameTileSize.y) + 1) / (_frameCount ? _frameCount : 1);
|
||||
(*_progressHandler)(percent_done, _progressHandlerContext);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _frameTileSize.y; i++) {
|
||||
for (int j = 0; j < _frameTileSize.x; j++) {
|
||||
Common::fill(tile_vector.begin(), tile_vector.end(), 0);
|
||||
|
||||
const uint32 *data_ptr = frame_data + j * GR_TILE_SPRITE_SIZE_X
|
||||
+ i * GR_TILE_SPRITE_SIZE_Y * _frameSize.x;
|
||||
|
||||
uint32 *tile_ptr = &tile_vector[0];
|
||||
for (int y = 0; y < GR_TILE_SPRITE_SIZE_Y; y++) {
|
||||
if (y + i * GR_TILE_SPRITE_SIZE_Y >= _frameSize.y) break;
|
||||
|
||||
for (int x = 0; x < GR_TILE_SPRITE_SIZE_X; x++) {
|
||||
if (x + j * GR_TILE_SPRITE_SIZE_X >= _frameSize.x) break;
|
||||
tile_ptr[x] = data_ptr[x];
|
||||
}
|
||||
|
||||
data_ptr += _frameSize.x;
|
||||
tile_ptr += GR_TILE_SPRITE_SIZE_X;
|
||||
}
|
||||
|
||||
int tile_id = -1;
|
||||
int tile_count = tileCount();
|
||||
for (int tile_idx = 0; tile_idx < tile_count; tile_idx++) {
|
||||
grTileSprite tile = getTile(tile_idx);
|
||||
if (tile == grTileSprite(&tile_vector[0])) {
|
||||
tile_id = tile_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tile_id == -1) {
|
||||
uint32 sz = GR_TILE_SPRITE_SIZE;
|
||||
uint32 offs = _tileOffsets.back();
|
||||
|
||||
for (auto &it : tile_vector)
|
||||
_tileData.push_back(it);
|
||||
|
||||
_tileOffsets.push_back(offs + sz);
|
||||
_frameIndex.push_back(tile_count);
|
||||
} else
|
||||
_frameIndex.push_back(tile_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool grTileAnimation::load(Common::SeekableReadStream *fh, int version) {
|
||||
int dL = (version >= 105) ? 2 : 7;
|
||||
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos start: %d", (int)fh->pos());
|
||||
|
||||
_frameCount = fh->readSint32LE();
|
||||
_frameSize.x = fh->readSint32LE();
|
||||
_frameSize.y = fh->readSint32LE();
|
||||
_frameTileSize.x = fh->readSint32LE();
|
||||
_frameTileSize.y = fh->readSint32LE();
|
||||
uint32 size = fh->readUint32LE();
|
||||
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): frameCount: %d, frame: %d x %d, tile: %d x %d, comp: %d", _frameCount, _frameSize.x, _frameSize.y,
|
||||
_frameTileSize.x, _frameTileSize.y, size);
|
||||
|
||||
_compression = grTileCompressionMethod(size);
|
||||
|
||||
if (version >= 105) {
|
||||
size = fh->readUint32LE();
|
||||
_scaleArray.resize(size);
|
||||
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos: %d _scaleArray size: %u", (int)fh->pos() - 4, size);
|
||||
|
||||
debugCN(dL + 1, kDebugLoad, " ");
|
||||
|
||||
for (uint i = 0; i < size; i++) {
|
||||
float scale = fh->readFloatLE();
|
||||
|
||||
addScale(i, scale);
|
||||
|
||||
debugCN(dL + 1, kDebugLoad, " %f, { %d x %d, [%d x %d], tiles: %d } ", _scaleArray[i]._scale,
|
||||
_scaleArray[i]._frameSize.x, _scaleArray[i]._frameSize.y, _scaleArray[i]._frameTileSize.x,
|
||||
_scaleArray[i]._frameTileSize.y, _scaleArray[i]._frameStart);
|
||||
}
|
||||
debugCN(dL + 1, kDebugLoad, "\n");
|
||||
}
|
||||
|
||||
_frameSizeArray.resize(_frameCount);
|
||||
|
||||
if (version < 106) {
|
||||
for (int i = 0; i < _frameCount; i++)
|
||||
_frameSizeArray[i] = _frameSize;
|
||||
} else {
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos: %d _frameSizeArray size: %u", (int)fh->pos() - 4, _frameCount);
|
||||
|
||||
debugCN(dL + 1, kDebugLoad, " ");
|
||||
|
||||
for (int i = 0; i < _frameCount; i++) {
|
||||
_frameSizeArray[i].x = fh->readUint32LE();
|
||||
_frameSizeArray[i].y = fh->readUint32LE();
|
||||
|
||||
debugCN(dL + 1, kDebugLoad, " %d x %d, ", _frameSizeArray[i].x, _frameSizeArray[i].y);
|
||||
}
|
||||
debugCN(dL + 1, kDebugLoad, "\n");
|
||||
}
|
||||
|
||||
size = fh->readUint32LE();
|
||||
_frameIndex.resize(size);
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos: %d _frameIndex size: %u", (int)fh->pos() - 4, size);
|
||||
|
||||
debugCN(dL + 2, kDebugLoad, " ");
|
||||
for (uint i = 0; i < size; i++) {
|
||||
_frameIndex[i] = fh->readUint32LE();
|
||||
debugCN(dL + 2, kDebugLoad, " %5d ", _frameIndex[i]);
|
||||
|
||||
if ((i + 1) % 20 == 0)
|
||||
debugCN(dL + 2, kDebugLoad, "\n ");
|
||||
}
|
||||
debugCN(dL + 2, kDebugLoad, "\n");
|
||||
|
||||
size = fh->readUint32LE();
|
||||
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos: %d _tileOffsets size: %u", (int)fh->pos() - 4, size);
|
||||
|
||||
_tileOffsets.resize(size);
|
||||
|
||||
debugCN(dL + 2, kDebugLoad, " ");
|
||||
for (uint i = 0; i < size; i++) {
|
||||
_tileOffsets[i] = fh->readUint32LE();
|
||||
debugCN(dL + 2, kDebugLoad, " %6d ", _tileOffsets[i]);
|
||||
|
||||
if ((i + 1) % 20 == 0)
|
||||
debugCN(dL + 2, kDebugLoad, "\n ");
|
||||
}
|
||||
debugCN(dL + 2, kDebugLoad, "\n");
|
||||
|
||||
size = fh->readUint32LE();
|
||||
|
||||
debugC(dL, kDebugLoad, "grTileAnimation::load(): pos: %d _tileData size: %u", (int)fh->pos() - 4, size);
|
||||
|
||||
_tileData.resize(size);
|
||||
|
||||
for (uint i = 0; i < size; i++)
|
||||
_tileData[i] = fh->readUint32LE();
|
||||
|
||||
debugC(dL + 1, kDebugLoad, " --> grTileAnimation::load(): pos: %d remaining: %d", (int)fh->pos(), (int)(fh->size() - fh->pos()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void grTileAnimation::drawFrame(const Vect2i &position, int32 frame_index, int32 mode, int closest_scale) const {
|
||||
debugC(3, kDebugGraphics, "grTileAnimation::drawFrame([%d, %d], frame: %d, mode: %d, scale_idx: %d)", position.x, position.y, frame_index, mode, closest_scale);
|
||||
|
||||
Vect2i frameSize = _frameSize;
|
||||
Vect2i frameTileSize = _frameTileSize;
|
||||
int frameStart = 0;
|
||||
|
||||
if (closest_scale != -1) {
|
||||
frameSize = _scaleArray[closest_scale]._frameSize;
|
||||
frameTileSize = _scaleArray[closest_scale]._frameTileSize;
|
||||
frameStart = _scaleArray[closest_scale]._frameStart;
|
||||
}
|
||||
|
||||
int xx = position.x - frameSize.x / 2;
|
||||
int yy = position.y - frameSize.y / 2;
|
||||
|
||||
int32 dx = GR_TILE_SPRITE_SIZE_X;
|
||||
int32 dy = GR_TILE_SPRITE_SIZE_Y;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
xx += frameSize.x - GR_TILE_SPRITE_SIZE_X;
|
||||
dx = -dx;
|
||||
}
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
yy += frameSize.y - GR_TILE_SPRITE_SIZE_Y;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
// grDispatcher::instance()->Rectangle(position.x - _frameSize.x/2, position.y - _frameSize.y/2, _frameSize.x, _frameSize.y, 0xFFFFF, 0, GR_OUTLINED);
|
||||
|
||||
const uint32 *index_ptr = &_frameIndex[frameStart] + frameTileSize.x * frameTileSize.y * frame_index;
|
||||
|
||||
int x = xx, y = yy;
|
||||
for (int32 i = 0; i < frameTileSize.y; i++) {
|
||||
x = xx;
|
||||
|
||||
for (int32 j = 0; j < frameTileSize.x; j++) {
|
||||
grDispatcher::instance()->putTileSpr(x, y, getTile(*index_ptr++), _hasAlpha, mode);
|
||||
x += dx;
|
||||
}
|
||||
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void grTileAnimation::drawFrame(const Vect2i &position, int frame_index, float angle, int mode) const {
|
||||
debugC(3, kDebugGraphics, "grTileAnimation::drawFrame([%d, %d], frame: %d, angle: %f, scale: %d)", position.x, position.y, frame_index, angle, mode);
|
||||
|
||||
byte *buf = decode_frame_data(frame_index, -1);
|
||||
Vect2i pos = position - _frameSize / 2;
|
||||
|
||||
grDispatcher::instance()->putSpr_rot(pos, _frameSize, buf, _hasAlpha, mode, angle);
|
||||
}
|
||||
|
||||
void grTileAnimation::drawFrame(const Vect2i &position, int frame_index, float angle, const Vect2f &scale, int mode) const {
|
||||
debugC(3, kDebugGraphics, "grTileAnimation::drawFrame([%d, %d], frame: %d, angle: %f, scale: [%f, %f], mode: %d)", position.x, position.y, frame_index, angle, scale.x, scale.y, mode);
|
||||
|
||||
byte *buf = decode_frame_data(frame_index, -1);
|
||||
Vect2i pos = position - _frameSize / 2;
|
||||
|
||||
grDispatcher::instance()->putSpr_rot(pos, _frameSize, buf, _hasAlpha, mode, angle, scale);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//// New version 105 & 106 code
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
grTileSprite grTileAnimation::getFrameTile(int frame_number, int tile_index) const {
|
||||
return getTile(_frameIndex[tile_index + frame_number * _frameTileSize.x * _frameTileSize.y]);
|
||||
}
|
||||
|
||||
bool grTileAnimation::hit(int frame_number, Vect2i &pos) const {
|
||||
int x = _frameSize.x / 2 + pos.x;
|
||||
int y = _frameSize.y / 2 + pos.y;
|
||||
|
||||
if (x < 0 || x >= _frameSize.x || y < 0 || y >= _frameSize.y)
|
||||
return false;
|
||||
|
||||
const byte *tile = (const byte *)getFrameTile(frame_number, x / 16 + y / 16 * _frameTileSize.x).data();
|
||||
|
||||
return tile[64 * (y % 16) + 4 * (x % 16) + 3] < 0xC8u;
|
||||
}
|
||||
|
||||
void grTileAnimation::drawFrame_scale(const Vect2i &position, int frame_index, float scale, int mode) const {
|
||||
debugC(3, kDebugGraphics, "grTileAnimation::drawFrame_scale([%d, %d], frame: %d, scale: %f, mode: %d)", position.x, position.y, frame_index, scale, mode);
|
||||
|
||||
int closest_scale = find_closest_scale(&scale);
|
||||
|
||||
if (wasFrameSizeChanged(frame_index, closest_scale, scale)) {
|
||||
byte *data = decode_frame_data(frame_index, closest_scale);
|
||||
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize =_scaleArray[closest_scale]._frameSize;
|
||||
|
||||
int x = position.x - round(float(frameSize.x) * scale) / 2;
|
||||
int y = position.y - round(float(frameSize.y) * scale) / 2;
|
||||
|
||||
grDispatcher::instance()->putSpr_a(x, y, frameSize.x, frameSize.y, data, mode, scale);
|
||||
} else {
|
||||
drawFrame(position, frame_index, mode, closest_scale);
|
||||
}
|
||||
}
|
||||
|
||||
void grTileAnimation::drawMask(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, int mode, int closest_scale) const {
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize =_scaleArray[closest_scale]._frameSize;
|
||||
|
||||
byte *buf = decode_frame_data(frame_index, closest_scale);
|
||||
|
||||
grDispatcher::instance()->putSprMask_a(pos.x - frameSize.x / 2, pos.y - frameSize.y / 2, frameSize.x, frameSize.y, buf, mask_colour, mask_alpha, mode);
|
||||
}
|
||||
|
||||
void grTileAnimation::drawMask_scale(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float scale, int mode) const {
|
||||
int closest_scale = find_closest_scale(&scale);
|
||||
|
||||
if (wasFrameSizeChanged(frame_index, closest_scale, scale)) {
|
||||
byte *buf = decode_frame_data(frame_index, closest_scale);
|
||||
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize =_scaleArray[closest_scale]._frameSize;
|
||||
|
||||
int x = pos.x - (int)((float)(frameSize.x / 2) * scale);
|
||||
int y = pos.y - (int)((float)(frameSize.y / 2) * scale);
|
||||
|
||||
grDispatcher::instance()->putSprMask_a(x, y, frameSize.x, frameSize.y, buf, mask_colour, mask_alpha, mode, scale);
|
||||
} else {
|
||||
drawMask(pos, frame_index, mask_colour, mask_alpha, mode, closest_scale);
|
||||
}
|
||||
}
|
||||
|
||||
void grTileAnimation::drawMask_rot(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float angle, int mode) const {
|
||||
byte *buf = decode_frame_data(frame_index, -1);
|
||||
|
||||
grDispatcher::instance()->putSprMask_rot(Vect2i(pos.x - _frameSize.x / 2, pos.y - _frameSize.y / 2), _frameSize, buf, _hasAlpha, mask_colour, mask_alpha, mode, angle);
|
||||
}
|
||||
|
||||
void grTileAnimation::drawMask_rot(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float angle, Vect2f scale, int mode) const {
|
||||
byte *buf = decode_frame_data(frame_index, -1);
|
||||
|
||||
int x = pos.x - (int)((float)(_frameSize.x / 2) * scale.x);
|
||||
int y = pos.y - (int)((float)(_frameSize.y / 2) * scale.y);
|
||||
|
||||
grDispatcher::instance()->putSprMask_rot(Vect2i(x, y), _frameSize, buf, _hasAlpha, mask_colour, mask_alpha, mode, angle, scale);
|
||||
}
|
||||
|
||||
void grTileAnimation::drawContour(const Vect2i &pos, int frame_index, uint32 color, int mode, int closest_scale) const {
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize =_scaleArray[closest_scale]._frameSize;
|
||||
|
||||
byte *buf = decode_frame_data(frame_index, closest_scale);
|
||||
|
||||
grDispatcher::instance()->drawSprContour_a(pos.x - frameSize.x / 2, pos.y - frameSize.y / 2, frameSize.x, frameSize.y, buf, color, mode);
|
||||
}
|
||||
|
||||
void grTileAnimation::drawContour(const Vect2i &pos, int frame_index, uint32 color, float scale, int mode) const {
|
||||
int closest_scale = find_closest_scale(&scale);
|
||||
|
||||
if (wasFrameSizeChanged(frame_index, closest_scale, scale)) {
|
||||
byte *data = decode_frame_data(frame_index, closest_scale);
|
||||
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize =_scaleArray[closest_scale]._frameSize;
|
||||
|
||||
int x = pos.x - (int)((float)(frameSize.x / 2) * scale);
|
||||
int y = pos.y - (int)((float)(frameSize.y / 2) * scale);
|
||||
|
||||
grDispatcher::instance()->drawSprContour_a(x, y, frameSize.x, frameSize.y, data, color, mode, scale);
|
||||
} else {
|
||||
drawContour(pos, frame_index, color, mode, closest_scale);
|
||||
}
|
||||
}
|
||||
|
||||
void grTileAnimation::addScale(int i, float scale) {
|
||||
_scaleArray[i]._scale = scale;
|
||||
_scaleArray[i]._frameSize.x = round((double)_frameSize.x * scale);
|
||||
_scaleArray[i]._frameSize.y = round((double)_frameSize.y * scale);
|
||||
_scaleArray[i]._frameTileSize.x = (_scaleArray[i]._frameSize.x + 15) / 16;
|
||||
_scaleArray[i]._frameTileSize.y = (_scaleArray[i]._frameSize.y + 15) / 16;
|
||||
|
||||
if (i == 0)
|
||||
_scaleArray[i]._frameStart = _frameTileSize.x * _frameTileSize.y * _frameCount;
|
||||
else
|
||||
_scaleArray[i]._frameStart = _scaleArray[i - 1]._frameStart
|
||||
+ _frameCount * _scaleArray[i - 1]._frameTileSize.y * _scaleArray[i - 1]._frameTileSize.x;
|
||||
}
|
||||
|
||||
byte *grTileAnimation::decode_frame_data(int frame_index, int closest_scale) const {
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize = _scaleArray[closest_scale]._frameSize;
|
||||
|
||||
Vect2i frameTileSize;
|
||||
if (closest_scale == -1)
|
||||
frameTileSize = _frameTileSize;
|
||||
else
|
||||
frameTileSize = _scaleArray[closest_scale]._frameTileSize;
|
||||
|
||||
int frameStart;
|
||||
if (closest_scale == -1)
|
||||
frameStart = 0;
|
||||
else
|
||||
frameStart = _scaleArray[closest_scale]._frameStart;
|
||||
|
||||
byte *buf = (byte *)grDispatcher::instance()->temp_buffer(frameSize.x * frameSize.y * 4);
|
||||
|
||||
const uint32 *index_ptr = &_frameIndex[frameStart] + frameTileSize.x * frameTileSize.y * frame_index;
|
||||
|
||||
for (int i = 0; i < frameTileSize.y; i++) {
|
||||
for (int j = 0; j < frameTileSize.x; j++) {
|
||||
byte *buf_ptr = buf + (i * frameSize.x * GR_TILE_SPRITE_SIZE_Y + j * GR_TILE_SPRITE_SIZE_X) * 4;
|
||||
|
||||
const byte *data_ptr = (const byte *)getTile(*index_ptr++).data();
|
||||
int dx = MIN(frameSize.x - j * GR_TILE_SPRITE_SIZE_X, GR_TILE_SPRITE_SIZE_X) * 4;
|
||||
int dy = MIN(frameSize.y - i * GR_TILE_SPRITE_SIZE_Y, GR_TILE_SPRITE_SIZE_Y);
|
||||
for (int k = 0; k < dy; k++) {
|
||||
memcpy(buf_ptr, data_ptr, dx);
|
||||
data_ptr += GR_TILE_SPRITE_SIZE_X * 4;
|
||||
buf_ptr += frameSize.x * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int grTileAnimation::find_closest_scale(float *scale) const {
|
||||
int idx = -1;
|
||||
float temp = 1.0;
|
||||
|
||||
for (uint i = 0; i < _scaleArray.size(); i++) {
|
||||
if (fabs(*scale - _scaleArray[i]._scale) < fabs(*scale - temp)) {
|
||||
idx = i;
|
||||
temp = _scaleArray[i]._scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx != -1)
|
||||
*scale = *scale / temp;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool grTileAnimation::wasFrameSizeChanged(int frame_index, int scaleIdx, float scale) const {
|
||||
int sx = _frameSizeArray[frame_index].x;
|
||||
int sy = _frameSizeArray[frame_index].y;
|
||||
|
||||
float newScale;
|
||||
|
||||
if (scaleIdx == -1)
|
||||
newScale = 1.0;
|
||||
else
|
||||
newScale = _scaleArray[scaleIdx]._scale;
|
||||
|
||||
if ((int)((float)sx * newScale * scale) == sx &&
|
||||
(int)((float)sy * newScale * scale) == sy)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface *grTileAnimation::dumpFrameTiles(int frame_index, float scale) const {
|
||||
int closest_scale = find_closest_scale(&scale);
|
||||
|
||||
Vect2i frameSize;
|
||||
|
||||
if (closest_scale == -1)
|
||||
frameSize = _frameSize;
|
||||
else
|
||||
frameSize = _scaleArray[closest_scale]._frameSize;
|
||||
|
||||
Vect2i frameTileSize;
|
||||
if (closest_scale == -1)
|
||||
frameTileSize = _frameTileSize;
|
||||
else
|
||||
frameTileSize = _scaleArray[closest_scale]._frameTileSize;
|
||||
|
||||
int frameStart;
|
||||
if (closest_scale == -1)
|
||||
frameStart = 0;
|
||||
else
|
||||
frameStart = _scaleArray[closest_scale]._frameStart;
|
||||
|
||||
int w = frameTileSize.x * (GR_TILE_SPRITE_SIZE_X + 1);
|
||||
int h = frameTileSize.y * (GR_TILE_SPRITE_SIZE_Y + 1);
|
||||
|
||||
Graphics::ManagedSurface *dstSurf = new Graphics::ManagedSurface(w, h, g_engine->_pixelformat);
|
||||
|
||||
int idx = frameStart + frameTileSize.x * frameTileSize.y * frame_index;
|
||||
int dx = grDispatcher::instance()->pixel_format() == GR_RGB565 ? 2 : 4;
|
||||
|
||||
for (int i = 0; i < frameTileSize.y; i++) {
|
||||
for (int j = 0; j < frameTileSize.x; j++) {
|
||||
if (idx >= (int)_frameIndex.size()) {
|
||||
warning("grTileAnimation::dumpFrameTiles(): overflow of frame index (%d > %d)", idx, _frameIndex.size());
|
||||
break;
|
||||
}
|
||||
|
||||
const byte *src = (const byte *)getTile(_frameIndex[idx++]).data();
|
||||
|
||||
for (int yy = 0; yy < GR_TILE_SPRITE_SIZE_Y; yy++) {
|
||||
byte *dst = (byte *)dstSurf->getBasePtr(j * (GR_TILE_SPRITE_SIZE_X + 1), i * (GR_TILE_SPRITE_SIZE_Y + 1) + yy);
|
||||
|
||||
for (int xx = 0; xx < GR_TILE_SPRITE_SIZE_X; xx++) {
|
||||
grDispatcher::instance()->setPixelFast(dst, grDispatcher::instance()->make_rgb(src[2], src[1], src[0]));
|
||||
dst += dx;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dstSurf;
|
||||
}
|
||||
|
||||
|
||||
Graphics::ManagedSurface *grTileAnimation::dumpTiles(int tilesPerRow) const {
|
||||
int w = tilesPerRow;
|
||||
int h = (_tileOffsets.size() + tilesPerRow - 1) / tilesPerRow;
|
||||
|
||||
Graphics::ManagedSurface *dstSurf = new Graphics::ManagedSurface(w * (GR_TILE_SPRITE_SIZE_X + 1), h * (GR_TILE_SPRITE_SIZE_Y + 1), g_engine->_pixelformat);
|
||||
|
||||
int index = 0;
|
||||
|
||||
int x = 0, y = 0;
|
||||
for (int32 i = 0; i < h; i++) {
|
||||
x = 0;
|
||||
|
||||
for (int32 j = 0; j < w; j++) {
|
||||
grDispatcher::instance()->putTileSpr(x, y, getTile(index++), _hasAlpha, 0, dstSurf, false);
|
||||
x += GR_TILE_SPRITE_SIZE_X + 1;
|
||||
|
||||
if (index >= (int)_tileOffsets.size())
|
||||
break;
|
||||
}
|
||||
|
||||
if (index >= (int)_tileOffsets.size())
|
||||
break;
|
||||
|
||||
y += GR_TILE_SPRITE_SIZE_X + 1;
|
||||
}
|
||||
|
||||
return dstSurf;
|
||||
}
|
||||
|
||||
void grTileAnimation::dumpTiles(Common::Path basename, int tilesPerRow) const {
|
||||
Common::Path path = Common::Path(Common::String::format("dumps/%s.tiles.png", transCyrillic(basename.baseName())));
|
||||
|
||||
Common::DumpFile bitmapFile;
|
||||
if (!bitmapFile.open(path, true)) {
|
||||
warning("Cannot dump tile into file '%s'", path.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface *dstSurf = dumpTiles(tilesPerRow);
|
||||
|
||||
|
||||
Image::writePNG(bitmapFile, *(dstSurf->surfacePtr()));
|
||||
bitmapFile.close();
|
||||
|
||||
warning("Dumped tile %s of %d x %d", path.toString().c_str(), dstSurf->w, dstSurf->h);
|
||||
|
||||
delete dstSurf;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
160
engines/qdengine/system/graphics/gr_tile_animation.h
Normal file
160
engines/qdengine/system/graphics/gr_tile_animation.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_GR_TILE_ANIMATION_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_GR_TILE_ANIMATION_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/path.h"
|
||||
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/system/graphics/gr_tile_sprite.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
typedef void (*CompressionProgressHandler)(int percents_loaded, void *context);
|
||||
|
||||
class grTileAnimation {
|
||||
public:
|
||||
grTileAnimation();
|
||||
|
||||
bool isEmpty() const {
|
||||
return !_frameCount;
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
int frameCount() const {
|
||||
return _frameCount;
|
||||
}
|
||||
const Vect2i &frameSize() const {
|
||||
return _frameSize;
|
||||
}
|
||||
const Vect2i &frameTileSize() const {
|
||||
return _frameTileSize;
|
||||
}
|
||||
int tileCount() const {
|
||||
return _tileOffsets.size() - 1;
|
||||
}
|
||||
|
||||
void init(int frame_count, const Vect2i &frame_size, bool alpha_flag);
|
||||
|
||||
void compact();
|
||||
|
||||
bool compress(grTileCompressionMethod method);
|
||||
|
||||
grTileSprite getTile(int tile_index) const;
|
||||
grTileSprite getFrameTile(int frame_number, int tile_index) const;
|
||||
|
||||
void addFrame(const uint32 *frame_data);
|
||||
|
||||
bool load(Common::SeekableReadStream *fh, int version);
|
||||
|
||||
void drawFrame(const Vect2i &position, int32 frame_index, int32 mode, int closest_scale) const;
|
||||
void drawFrame(const Vect2i &position, int frame_index, float angle, int mode = 0) const;
|
||||
void drawFrame(const Vect2i &position, int frame_index, float angle, const Vect2f &scale, int mode) const;
|
||||
|
||||
void drawFrame_scale(const Vect2i &position, int frame_index, float scale, int mode) const;
|
||||
|
||||
void drawMask(const Vect2i &position, int frame_index, uint32 mask_color, int mask_alpha, int mode, int closest_scale) const;
|
||||
void drawMask_scale(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float scale, int mode) const;
|
||||
void drawMask_rot(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float angle, int mode) const;
|
||||
void drawMask_rot(const Vect2i &pos, int frame_index, uint32 mask_colour, int mask_alpha, float angle, Vect2f scale, int mode) const;
|
||||
|
||||
void drawContour(const Vect2i &position, int frame_index, uint32 color, int mode, int closest_scale) const;
|
||||
void drawContour(const Vect2i &position, int frame_index, uint32 color, float scale, int mode) const;
|
||||
|
||||
bool hit(int frame_number, Vect2i &pos) const;
|
||||
|
||||
static void setProgressHandler(CompressionProgressHandler handler, void *context) {
|
||||
_progressHandler = handler;
|
||||
_progressHandlerContext = context;
|
||||
}
|
||||
|
||||
void addScale(int i, float scale);
|
||||
byte *decode_frame_data(int frame_index, int closest_scale) const;
|
||||
int find_closest_scale(float *scale) const;
|
||||
bool wasFrameSizeChanged(int frame_index, int scaleIdx, float scale) const;
|
||||
|
||||
Graphics::ManagedSurface *dumpTiles(int tilesPerRow) const;
|
||||
void dumpTiles(Common::Path baseName, int tilesPerRow) const;
|
||||
|
||||
Graphics::ManagedSurface *dumpFrameTiles(int frame_index, float scale) const;
|
||||
|
||||
private:
|
||||
|
||||
grTileCompressionMethod _compression;
|
||||
|
||||
/// true если есть альфа-канал
|
||||
bool _hasAlpha;
|
||||
|
||||
/// размеры кадра в пикселах
|
||||
/// могут быть невыровненными по рамерам тайла
|
||||
Vect2i _frameSize;
|
||||
|
||||
/// размеры кадра в тайлах
|
||||
Vect2i _frameTileSize;
|
||||
|
||||
/// количество кадров
|
||||
int _frameCount;
|
||||
|
||||
typedef Std::vector<uint32> FrameIndex;
|
||||
|
||||
struct ScaleArray {
|
||||
float _scale;
|
||||
Vect2i _frameSize;
|
||||
Vect2i _frameTileSize;
|
||||
int _frameStart;
|
||||
};
|
||||
|
||||
Std::vector<ScaleArray> _scaleArray;
|
||||
|
||||
/// индекс кадров - номера тайлов, из которых состоят кадры
|
||||
/// _frameTileSize.x * _frameTileSize.y на кадр
|
||||
FrameIndex _frameIndex;
|
||||
|
||||
typedef Std::vector<uint32> TileOffsets;
|
||||
/// смещения до данных каждого тайла
|
||||
TileOffsets _tileOffsets;
|
||||
typedef Std::vector<uint32> TileData;
|
||||
/// данные тайлов
|
||||
TileData _tileData;
|
||||
|
||||
mutable Common::HashMap<uint32, grTileSprite> _decompressedTiles;
|
||||
|
||||
Std::vector<Vect2i> _frameSizeArray;
|
||||
|
||||
static CompressionProgressHandler _progressHandler;
|
||||
static void *_progressHandlerContext;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_GR_TILE_ANIMATION_H
|
||||
211
engines/qdengine/system/graphics/gr_tile_sprite.cpp
Normal file
211
engines/qdengine/system/graphics/gr_tile_sprite.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/graphics/gr_tile_sprite.h"
|
||||
#include "qdengine/qdcore/util/LZ77.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
uint32 grTileSprite::_comprasionTolerance = 2;
|
||||
|
||||
namespace tile_compress {
|
||||
|
||||
const uint32 RLE_SEQUENCE_MASK = 1 << (GR_TILE_SPRITE_SIZE_SHIFT * 2 + 1);
|
||||
|
||||
uint32 encodeRLE(const uint32 *in_data, uint32 *out_data) {
|
||||
uint32 size = 0;
|
||||
|
||||
int count = 0;
|
||||
while (count < GR_TILE_SPRITE_SIZE) {
|
||||
int index = count;
|
||||
uint32 pixel = in_data[index++];
|
||||
|
||||
while (index < GR_TILE_SPRITE_SIZE && in_data[index] == pixel)
|
||||
index++;
|
||||
|
||||
if (index - count == 1) {
|
||||
while (index < GR_TILE_SPRITE_SIZE && (in_data[index] != in_data[index - 1] || (index > 1 && in_data[index] != in_data[index - 2])))
|
||||
index++;
|
||||
|
||||
while (index < GR_TILE_SPRITE_SIZE && in_data[index] == in_data[index - 1])
|
||||
index --;
|
||||
|
||||
out_data[size] = index - count;
|
||||
out_data[size] |= RLE_SEQUENCE_MASK;
|
||||
size++;
|
||||
|
||||
for (int i = count; i < index; i++)
|
||||
out_data[size++] = in_data[i];
|
||||
} else {
|
||||
out_data[size++] = index - count;
|
||||
out_data[size++] = pixel;
|
||||
}
|
||||
|
||||
count = index;
|
||||
assert(index < GR_TILE_SPRITE_SIZE * 4);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool decodeRLE(const uint32 *in_data, uint32 *out_data) {
|
||||
const uint32 *in_buf = in_data;
|
||||
uint32 *out_buf = out_data;
|
||||
|
||||
int out_size = 0;
|
||||
while (out_size < GR_TILE_SPRITE_SIZE) {
|
||||
uint32 count = *in_buf++;
|
||||
if (count & RLE_SEQUENCE_MASK) {
|
||||
count ^= RLE_SEQUENCE_MASK;
|
||||
for (uint i = 0; i < count; i++)
|
||||
*out_buf++ = *in_buf++;
|
||||
} else {
|
||||
uint32 color = *in_buf++;
|
||||
for (uint i = 0; i < count; i++)
|
||||
*out_buf++ = color;
|
||||
}
|
||||
|
||||
out_size += count;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace tile_compress
|
||||
|
||||
void grDispatcher::putTileSpr(int x, int y, const grTileSprite &sprite, bool has_alpha, int mode, Graphics::ManagedSurface *surf, bool clip) {
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
int psx = GR_TILE_SPRITE_SIZE_X;
|
||||
int psy = GR_TILE_SPRITE_SIZE_Y;
|
||||
|
||||
if (clip && !clip_rectangle(x, y, px, py, psx, psy))
|
||||
return;
|
||||
|
||||
int dx = -2;
|
||||
int dy = -1;
|
||||
|
||||
if (mode & GR_FLIP_HORIZONTAL) {
|
||||
x += psx - 1;
|
||||
px = GR_TILE_SPRITE_SIZE_X - px - psx;
|
||||
} else
|
||||
dx = 2;
|
||||
|
||||
if (_pixel_format == GR_RGBA8888)
|
||||
dx *= 2;
|
||||
|
||||
if (mode & GR_FLIP_VERTICAL) {
|
||||
y += psy - 1;
|
||||
py = GR_TILE_SPRITE_SIZE_Y - py - psy;
|
||||
} else
|
||||
dy = 1;
|
||||
|
||||
if (!surf)
|
||||
surf = _screenBuf;
|
||||
|
||||
const byte *data_ptr = (const byte *)(sprite.data() + px + py * GR_TILE_SPRITE_SIZE_X);
|
||||
|
||||
for (int i = 0; i < psy; i++) {
|
||||
byte *scr_buf = reinterpret_cast<byte *>(surf->getBasePtr(x, y));
|
||||
const byte *data_line = data_ptr;
|
||||
|
||||
for (int j = 0; j < psx; j++) {
|
||||
uint32 a = data_line[3];
|
||||
if (a != 255) {
|
||||
if (_pixel_format == GR_RGB565) {
|
||||
if (a)
|
||||
setPixelFast(scr_buf, alpha_blend_565(make_rgb565u(data_line[2], data_line[1], data_line[0]), *(uint16 *)scr_buf, a));
|
||||
else
|
||||
setPixelFast(scr_buf, make_rgb565u(data_line[2], data_line[1], data_line[0]));
|
||||
} else {
|
||||
if (a) {
|
||||
scr_buf[1] = data_line[0] + ((a * scr_buf[1]) >> 8);
|
||||
scr_buf[2] = data_line[1] + ((a * scr_buf[2]) >> 8);
|
||||
scr_buf[3] = data_line[2] + ((a * scr_buf[3]) >> 8);
|
||||
} else {
|
||||
scr_buf[1] = data_line[0];
|
||||
scr_buf[2] = data_line[1];
|
||||
scr_buf[3] = data_line[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
scr_buf += dx;
|
||||
data_line += 4;
|
||||
}
|
||||
data_ptr += GR_TILE_SPRITE_SIZE_X * 4;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
grTileSprite::grTileSprite(const uint32 *data_ptr) : _data(data_ptr) {
|
||||
}
|
||||
|
||||
bool grTileSprite::operator == (const grTileSprite &sprite) const {
|
||||
if (isEmpty() || sprite.isEmpty())
|
||||
return (isEmpty() && sprite.isEmpty());
|
||||
|
||||
const byte *ptr0 = (const byte *)_data;
|
||||
const byte *ptr1 = (const byte *)sprite._data;
|
||||
|
||||
for (int i = 0; i < GR_TILE_SPRITE_SIZE_BYTES; i++, ptr0++, ptr1++) {
|
||||
if ((uint)abs(*ptr0 - *ptr1) > _comprasionTolerance)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 grTileSprite::compress(const uint32 *in_data, uint32 *out_data, grTileCompressionMethod compress_method) {
|
||||
if (compress_method == TILE_COMPRESS_RLE) {
|
||||
return tile_compress::encodeRLE(in_data, out_data);
|
||||
} else if (compress_method == TILE_COMPRESS_LZ77) {
|
||||
CLZ77 encoder;
|
||||
int32 len = 0;
|
||||
encoder.encode((byte *)(out_data + 1), len, (const byte *)in_data, GR_TILE_SPRITE_SIZE_BYTES);
|
||||
assert(len);
|
||||
out_data[0] = len;
|
||||
return len / 4 + 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool grTileSprite::uncompress(const uint32 *in_data, uint32 in_data_length, uint32 *out_data, grTileCompressionMethod compress_method) {
|
||||
if (compress_method == TILE_COMPRESS_RLE) {
|
||||
return tile_compress::decodeRLE(in_data, out_data);
|
||||
} else if (compress_method == TILE_COMPRESS_LZ77) {
|
||||
CLZ77 decoder;
|
||||
int32 len = 0;
|
||||
in_data_length = in_data[0];
|
||||
decoder.decode((byte *)out_data, len, (const byte *)(in_data + 1), in_data_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
78
engines/qdengine/system/graphics/gr_tile_sprite.h
Normal file
78
engines/qdengine/system/graphics/gr_tile_sprite.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_GR_TILE_SPRITE_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_GR_TILE_SPRITE_H
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const int GR_TILE_SPRITE_SIZE_SHIFT = 4;
|
||||
const int GR_TILE_SPRITE_SIZE_X = 1 << GR_TILE_SPRITE_SIZE_SHIFT;
|
||||
const int GR_TILE_SPRITE_SIZE_Y = 1 << GR_TILE_SPRITE_SIZE_SHIFT;
|
||||
|
||||
const int GR_TILE_SPRITE_SIZE = GR_TILE_SPRITE_SIZE_X * GR_TILE_SPRITE_SIZE_Y;
|
||||
const int GR_TILE_SPRITE_SIZE_BYTES = GR_TILE_SPRITE_SIZE * 4;
|
||||
|
||||
enum grTileCompressionMethod {
|
||||
TILE_UNCOMPRESSED,
|
||||
TILE_COMPRESS_RLE,
|
||||
TILE_COMPRESS_LZ77
|
||||
};
|
||||
|
||||
/// Тайл-спрайт
|
||||
|
||||
/// Квадратный 32х битный спрайт фиксированного размера.
|
||||
/// Данные внешние.
|
||||
class grTileSprite {
|
||||
public:
|
||||
grTileSprite(const uint32 *data_ptr = 0);
|
||||
|
||||
bool operator == (const grTileSprite &sprite) const;
|
||||
|
||||
bool isEmpty() const {
|
||||
return !_data;
|
||||
}
|
||||
|
||||
const uint32 *data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
static uint32 comprasionTolerance() {
|
||||
return _comprasionTolerance;
|
||||
}
|
||||
static void setComprasionTolerance(uint32 value) {
|
||||
_comprasionTolerance = value;
|
||||
}
|
||||
|
||||
static uint32 compress(const uint32 *in_data, uint32 *out_data, grTileCompressionMethod compress_method);
|
||||
static bool uncompress(const uint32 *in_data, uint32 in_data_length, uint32 *out_data, grTileCompressionMethod compress_method);
|
||||
|
||||
private:
|
||||
|
||||
const uint32 *_data;
|
||||
|
||||
/// толерантность побайтового сравнения данных, [0, 255]
|
||||
static uint32 _comprasionTolerance;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_GR_TILE_SPRITE_H
|
||||
362
engines/qdengine/system/graphics/rle_compress.cpp
Normal file
362
engines/qdengine/system/graphics/rle_compress.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/std/vector.h"
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "qdengine/system/graphics/rle_compress.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
byte *g_buffer0 = nullptr;
|
||||
byte *g_buffer1 = nullptr;
|
||||
uint32 g_buffersLen = 0;
|
||||
|
||||
static void ensureBuffers() {
|
||||
if (g_buffer0 == nullptr) {
|
||||
g_buffer0 = (byte *)calloc(4096, 1);
|
||||
g_buffer1 = (byte *)calloc(4096, 1);
|
||||
|
||||
g_buffersLen = 4096U;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator == (const RLEBuffer &buf1, const RLEBuffer &buf2) {
|
||||
if (!(buf1._header_offset == buf2._header_offset)) return false;
|
||||
if (!(buf1._data_offset == buf2._data_offset)) return false;
|
||||
if (!(buf1._header == buf2._header)) return false;
|
||||
if (!(buf1._data == buf2._data)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RLEBuffer::RLEBuffer() : _bits_per_pixel(32) {
|
||||
}
|
||||
|
||||
RLEBuffer::RLEBuffer(const RLEBuffer &buf) : _header_offset(buf._header_offset),
|
||||
_data_offset(buf._data_offset),
|
||||
_header(buf._header),
|
||||
_data(buf._data),
|
||||
_bits_per_pixel(buf._bits_per_pixel) {
|
||||
|
||||
ensureBuffers();
|
||||
}
|
||||
|
||||
RLEBuffer::~RLEBuffer() {
|
||||
_header_offset.clear();
|
||||
_data_offset.clear();
|
||||
_header.clear();
|
||||
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
bool RLEBuffer::decode_line(int y, int buffer_id) const {
|
||||
ensureBuffers();
|
||||
|
||||
if (buffer_id)
|
||||
return decode_line(y, g_buffer1);
|
||||
else
|
||||
return decode_line(y, g_buffer0);
|
||||
}
|
||||
|
||||
const byte *RLEBuffer::get_buffer(int buffer_id) {
|
||||
ensureBuffers();
|
||||
|
||||
if (buffer_id)
|
||||
return g_buffer1;
|
||||
else
|
||||
return g_buffer0;
|
||||
}
|
||||
|
||||
void RLEBuffer::releaseBuffers() {
|
||||
free(g_buffer0);
|
||||
g_buffer0 = nullptr;
|
||||
free(g_buffer1);
|
||||
g_buffer1 = nullptr;
|
||||
}
|
||||
|
||||
RLEBuffer &RLEBuffer::operator = (const RLEBuffer &buf) {
|
||||
if (this == &buf) return *this;
|
||||
|
||||
_header_offset = buf._header_offset;
|
||||
_data_offset = buf._data_offset;
|
||||
|
||||
_header = buf._header;
|
||||
_data = buf._data;
|
||||
|
||||
_bits_per_pixel = buf._bits_per_pixel;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RLEBuffer::encode(int sx, int sy, const byte *buf) {
|
||||
_header_offset.resize(sy);
|
||||
_data_offset.resize(sy);
|
||||
|
||||
_header.clear();
|
||||
_data.clear();
|
||||
|
||||
_data.reserve(sx * sy);
|
||||
|
||||
const uint32 *buffer = reinterpret_cast<const uint32 *>(buf);
|
||||
|
||||
for (int y = 0; y < sy; y++) {
|
||||
int count = 0;
|
||||
|
||||
_header_offset[y] = _header.size();
|
||||
_data_offset[y] = _data.size();
|
||||
|
||||
while (count < sx) {
|
||||
int index = count;
|
||||
uint32 pixel = buffer[index++];
|
||||
|
||||
while (index < sx && index - count < 127 && buffer[index] == pixel)
|
||||
index++;
|
||||
|
||||
if (index - count == 1) {
|
||||
while (index < sx && index - count < 127 && (buffer[index] != buffer[index - 1] || (index > 1 && buffer[index] != buffer[index - 2])))
|
||||
index++;
|
||||
|
||||
while (index < sx && buffer[index] == buffer[index - 1])
|
||||
index--;
|
||||
|
||||
_header.push_back(static_cast<int8>(count - index));
|
||||
for (int i = count; i < index; i++)
|
||||
_data.push_back(buffer[i]);
|
||||
} else {
|
||||
_header.push_back(static_cast<int8>(index - count));
|
||||
_data.push_back(pixel);
|
||||
}
|
||||
|
||||
count = index;
|
||||
}
|
||||
buffer += sx;
|
||||
}
|
||||
Std::vector<uint32>(_data).swap(_data);
|
||||
|
||||
resize_buffers();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RLEBuffer::decode_line(int y, byte *out_buf) const {
|
||||
const int8 *header_ptr = &*(_header.begin() + _header_offset[y]);
|
||||
const uint32 *data_ptr = &*(_data.begin() + _data_offset[y]);
|
||||
|
||||
uint32 *out_ptr = reinterpret_cast<uint32 *>(out_buf);
|
||||
|
||||
int size = line_header_length(y);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int8 count = *header_ptr++;
|
||||
if (count > 0) {
|
||||
for (int j = 0; j < count; j++)
|
||||
*out_ptr++ = *data_ptr;
|
||||
data_ptr++;
|
||||
} else {
|
||||
count = -count;
|
||||
memcpy(out_ptr, data_ptr, count * sizeof(uint32));
|
||||
|
||||
out_ptr += count;
|
||||
data_ptr += count;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RLEBuffer::decode_pixel(int x, int y, uint32 &pixel) {
|
||||
const int8 *header_ptr = &*(_header.begin() + _header_offset[y]);
|
||||
const uint32 *data_ptr = &*(_data.begin() + _data_offset[y]);
|
||||
|
||||
int xx = 0;
|
||||
int8 count = *header_ptr++;
|
||||
|
||||
while (xx + abs(count) < x) {
|
||||
if (count > 0) {
|
||||
data_ptr++;
|
||||
} else {
|
||||
count = -count;
|
||||
data_ptr += count;
|
||||
}
|
||||
xx += count;
|
||||
count = *header_ptr++;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
pixel = *data_ptr;
|
||||
} else {
|
||||
data_ptr += x - xx;
|
||||
pixel = *data_ptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 RLEBuffer::size() {
|
||||
return _data.size() * sizeof(uint32) + _data_offset.size() + _header_offset.size() * sizeof(uint32) + _header.size();
|
||||
}
|
||||
|
||||
bool RLEBuffer::convert_data(int bits_per_pixel) {
|
||||
if (_bits_per_pixel == bits_per_pixel)
|
||||
return true;
|
||||
|
||||
int sz = _data.size();
|
||||
|
||||
switch (_bits_per_pixel) {
|
||||
case 15:
|
||||
case 16:
|
||||
if (bits_per_pixel == 24 || bits_per_pixel == 32) {
|
||||
uint16 *short_ptr = reinterpret_cast<uint16 *>(&*_data.begin());
|
||||
|
||||
for (int i = 0; i < sz; i++) {
|
||||
short_ptr++;
|
||||
*short_ptr++ <<= 8;
|
||||
}
|
||||
|
||||
short_ptr = reinterpret_cast<uint16 *>(&*_data.begin());
|
||||
byte *char_ptr = reinterpret_cast<byte *>(&*_data.begin());
|
||||
|
||||
for (int i = 0; i < sz; i++) {
|
||||
byte r, g, b;
|
||||
|
||||
if (_bits_per_pixel == 15)
|
||||
grDispatcher::split_rgb555u(*short_ptr++, r, g, b);
|
||||
else
|
||||
grDispatcher::split_rgb565u(*short_ptr++, r, g, b);
|
||||
|
||||
short_ptr++;
|
||||
|
||||
char_ptr[0] = b;
|
||||
char_ptr[1] = g;
|
||||
char_ptr[2] = r;
|
||||
|
||||
char_ptr += 4;
|
||||
}
|
||||
} else {
|
||||
uint16 *short_ptr = reinterpret_cast<uint16 *>(&*_data.begin());
|
||||
|
||||
for (int i = 0; i < sz; i++) {
|
||||
byte r, g, b;
|
||||
|
||||
if (_bits_per_pixel == 15) {
|
||||
grDispatcher::split_rgb555u(*short_ptr, r, g, b);
|
||||
*short_ptr++ = grDispatcher::make_rgb565u(r, g, b);
|
||||
} else {
|
||||
grDispatcher::split_rgb565u(*short_ptr, r, g, b);
|
||||
*short_ptr++ = grDispatcher::make_rgb555u(r, g, b);
|
||||
}
|
||||
|
||||
short_ptr++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
if (bits_per_pixel == 15 || bits_per_pixel == 16) {
|
||||
byte *src_ptr = reinterpret_cast<byte *>(&*_data.begin());
|
||||
uint16 *dest_ptr = reinterpret_cast<uint16 *>(&*_data.begin());
|
||||
|
||||
for (int i = 0; i < sz; i++) {
|
||||
*dest_ptr++ = (bits_per_pixel == 15) ? grDispatcher::make_rgb555u(src_ptr[2], src_ptr[1], src_ptr[0]) : grDispatcher::make_rgb565u(src_ptr[2], src_ptr[1], src_ptr[0]);
|
||||
*dest_ptr++ >>= 8;
|
||||
src_ptr += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_bits_per_pixel = bits_per_pixel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RLEBuffer::resize_buffers() {
|
||||
uint32 len = line_length() * sizeof(uint32);
|
||||
|
||||
if (g_buffersLen < len) {
|
||||
if (!(g_buffer0 = (byte *)realloc(g_buffer0, len)) || !(g_buffer1 = (byte *)realloc(g_buffer1, len)))
|
||||
error("RLEBuffer::resize_buffers(): Cannot realloc buffers");
|
||||
|
||||
g_buffersLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
int RLEBuffer::line_length() {
|
||||
if (_header_offset.empty()) return 0;
|
||||
|
||||
uint sz = (_header_offset.size() > 1) ? _header_offset[1] : _header.size();
|
||||
|
||||
uint len = 0;
|
||||
for (uint i = 0; i < sz; i++) {
|
||||
len += abs(_header[i]);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int RLEBuffer::line_header_length(int line_num) const {
|
||||
if (line_num < (int)_header_offset.size() - 1)
|
||||
return _header_offset[line_num + 1] - _header_offset[line_num];
|
||||
else
|
||||
return _header.size() - _header_offset[line_num];
|
||||
}
|
||||
|
||||
|
||||
bool RLEBuffer::load(Common::SeekableReadStream *fh) {
|
||||
uint32 sz = fh->readUint32LE();
|
||||
_header_offset.resize(sz);
|
||||
|
||||
sz = fh->readSint32LE();
|
||||
_data_offset.resize(sz);
|
||||
|
||||
sz = fh->readSint32LE();
|
||||
_header.resize(sz + 1);
|
||||
_header[sz] = 0;
|
||||
|
||||
sz = fh->readSint32LE();
|
||||
_data.resize(sz);
|
||||
|
||||
for (uint i = 0; i < _header_offset.size(); i++) {
|
||||
_header_offset[i] = fh->readUint32LE();
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _data_offset.size(); i++) {
|
||||
_data_offset[i] = fh->readUint32LE();
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _header.size() - 1; i++) {
|
||||
_header[i] = fh->readByte();
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _data.size(); i++) {
|
||||
_data[i] = fh->readUint32LE();
|
||||
}
|
||||
|
||||
resize_buffers();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
87
engines/qdengine/system/graphics/rle_compress.h
Normal file
87
engines/qdengine/system/graphics/rle_compress.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_SYSTEM_GRAPHICS_RLE_COMPRESS_H
|
||||
#define QDENGINE_SYSTEM_GRAPHICS_RLE_COMPRESS_H
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Массив, сжатый методом RLE.
|
||||
class RLEBuffer {
|
||||
public:
|
||||
RLEBuffer();
|
||||
RLEBuffer(const RLEBuffer &buf);
|
||||
~RLEBuffer();
|
||||
|
||||
RLEBuffer &operator = (const RLEBuffer &buf);
|
||||
|
||||
bool encode(int sx, int sy, const byte *buf);
|
||||
|
||||
bool decode_line(int y, byte *out_buf) const;
|
||||
|
||||
bool decode_line(int y, int buffer_id = 0) const;
|
||||
|
||||
bool decode_pixel(int x, int y, uint32 &pixel);
|
||||
|
||||
static const byte *get_buffer(int buffer_id);
|
||||
|
||||
void resize_buffers();
|
||||
|
||||
uint32 size();
|
||||
int line_length();
|
||||
int line_header_length(int line_num) const;
|
||||
|
||||
uint32 header_size() const {
|
||||
return _header.size();
|
||||
}
|
||||
uint32 data_size() const {
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
const int8 *header_ptr(int y = 0) const {
|
||||
return &*(_header.begin() + _header_offset[y]);
|
||||
}
|
||||
const uint32 *data_ptr(int y = 0) const {
|
||||
return &*(_data.begin() + _data_offset[y]);
|
||||
}
|
||||
|
||||
bool load(Common::SeekableReadStream *fh);
|
||||
|
||||
bool convert_data(int bits_per_pixel = 16);
|
||||
|
||||
static void releaseBuffers();
|
||||
|
||||
private:
|
||||
Std::vector<uint32> _header_offset;
|
||||
Std::vector<uint32> _data_offset;
|
||||
|
||||
Std::vector<int8> _header;
|
||||
Std::vector<uint32> _data;
|
||||
|
||||
int _bits_per_pixel;
|
||||
|
||||
friend bool operator == (const RLEBuffer &buf1, const RLEBuffer &buf2);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_SYSTEM_GRAPHICS_RLE_COMPRESS_H
|
||||
Reference in New Issue
Block a user