Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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 &reg);
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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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 &reg) 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 &reg) 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 &reg) {
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

View 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

View 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

View 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

View 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

View 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

View 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