aboutsummaryrefslogtreecommitdiff
path: root/engines/startrek/graphics.cpp
diff options
context:
space:
mode:
authorMatthew Stewart2018-02-23 02:11:40 -0500
committerEugene Sandulenko2018-08-09 08:37:30 +0200
commitcd45502501787c8003cfd86b7adf48a6f86d68de (patch)
tree1d2a917fba484f3a5c7b4333ed290cb430bc3f92 /engines/startrek/graphics.cpp
parentc71a8a6d2acb3be145731e6af344cb16a38c6b46 (diff)
downloadscummvm-rg350-cd45502501787c8003cfd86b7adf48a6f86d68de.tar.gz
scummvm-rg350-cd45502501787c8003cfd86b7adf48a6f86d68de.tar.bz2
scummvm-rg350-cd45502501787c8003cfd86b7adf48a6f86d68de.zip
STARTREK: Implement draw modes 2 and 3 for sprites
Diffstat (limited to 'engines/startrek/graphics.cpp')
-rwxr-xr-xengines/startrek/graphics.cpp216
1 files changed, 155 insertions, 61 deletions
diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp
index acedd72ea1..c597568614 100755
--- a/engines/startrek/graphics.cpp
+++ b/engines/startrek/graphics.cpp
@@ -17,10 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm-startrek.googlecode.com/svn/trunk/graphics.cpp $
- * $Id: graphics.cpp 14 2010-05-26 15:44:12Z clone2727 $
- *
*/
#include "startrek/graphics.h"
@@ -31,33 +27,14 @@
namespace StarTrek {
-// Bitmap class
-
-Bitmap::Bitmap(Common::ReadStreamEndian *stream) {
- xoffset = stream->readUint16();
- yoffset = stream->readUint16();
- width = stream->readUint16();
- height = stream->readUint16();
-
- pixels = (byte*)malloc(width*height);
- stream->read(pixels, width*height);
-}
-
-Bitmap::Bitmap(int w, int h) : width(w), height(h) {
- pixels = (byte*)malloc(width*height);
-}
-
-Bitmap::~Bitmap() {
- free(pixels);
-}
-
+Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) {
+ _font = nullptr;
-// Graphics class
+ _egaData = nullptr;
+ _priData = nullptr;
+ _lutData = nullptr;
-Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) {
- _font = 0;
- _egaData = 0;
- _priData = 0;
+ _screenRect = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
if (ConfMan.hasKey("render_mode"))
_egaMode = (Common::parseRenderMode(ConfMan.get("render_mode").c_str()) == Common::kRenderEGA) && (_vm->getGameType() != GType_STJR) && !(_vm->getFeatures() & GF_DEMO);
@@ -70,20 +47,21 @@ Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) {
}
Graphics::~Graphics() {
- if (_egaData)
- free(_egaData);
- if (_priData)
- free(_priData);
+ delete[] _egaData;
+ delete[] _priData;
+ delete[] _lutData;
delete _font;
delete _backgroundImage;
delete _canvas;
}
-void Graphics::loadPalette(const char *paletteFile) {
+void Graphics::loadPalette(const Common::String &paletteName) {
// Set the palette from a PAL file
+ Common::String palFile = paletteName + ".PAL";
+ Common::String lutFile = paletteName + ".LUT";
- Common::SeekableReadStream *palStream = _vm->openFile(paletteFile);
+ Common::SeekableReadStream *palStream = _vm->openFile(palFile.c_str());
byte *palette = new byte[256 * 3];
palStream->read(palette, 256 * 3);
@@ -96,13 +74,22 @@ void Graphics::loadPalette(const char *paletteFile) {
delete[] palette;
delete palStream;
+
+ // Load LUT file
+ Common::SeekableReadStream *lutStream = _vm->openFile(lutFile.c_str());
+
+ delete[] _lutData;
+ _lutData = new byte[256];
+ lutStream->read(_lutData, 256);
+
+ delete lutStream;
}
void Graphics::loadPri(const char *priFile) {
Common::SeekableReadStream *priStream = _vm->openFile(priFile);
- free(_priData);
- _priData = (byte*)malloc(SCREEN_WIDTH*SCREEN_HEIGHT/2);
+ delete[] _priData;
+ _priData = new byte[SCREEN_WIDTH*SCREEN_HEIGHT/2];
priStream->read(_priData, SCREEN_WIDTH*SCREEN_HEIGHT/2);
}
@@ -110,70 +97,177 @@ void Graphics::redrawScreen() {
// TODO: get rid of _canvas for efficiency
memcpy(_canvas->pixels, _backgroundImage->pixels, SCREEN_WIDTH*SCREEN_HEIGHT);
- // drawSprite test
+ // drawSprite tests
+
+ // Draw mode 0
Sprite spr;
memset(&spr,0,sizeof(Sprite));
spr.bitmap = new Bitmap(_vm->openFile("MWALKE00.BMP"));
spr.drawPriority = 1;
spr.drawX = 150;
spr.drawY = 30;
+ spr.drawMode = 0;
+ drawSprite(spr);
+
+ // Draw mode 2 (translucent background)
+ memset(&spr,0,sizeof(Sprite));
+ spr.bitmap = new Bitmap(_vm->openFile("KWALKS00.BMP"));
+ spr.drawPriority = 1;
+ spr.drawX = 200;
+ spr.drawY = 40;
+ spr.drawMode = 2;
+ drawSprite(spr);
- drawSprite(spr, Common::Rect(spr.drawX,spr.drawY,spr.drawX+spr.bitmap->width,spr.drawY+spr.bitmap->height));
+ // Draw mode 3 (text)
+ memset(&spr,0,sizeof(Sprite));
+ spr.bitmap = new Bitmap(8*8,8*8);
+ for (int i=0;i<8*8;i++)
+ spr.bitmap->pixels[i] = 0x40+i;
+ spr.drawX = 8*10;
+ spr.drawY = 50;
+ spr.textColor = 0xb3;
+ spr.drawMode = 3;
+ drawSprite(spr);
drawBitmapToScreen(_canvas);
}
-// rect is the rectangle on-screen to draw. It should encompass the sprite itself, but if
-// it doesn't, part of the sprite will be cut off.
+void Graphics::drawSprite(const Sprite &sprite) {
+ drawSprite(sprite, Common::Rect(sprite.drawX,sprite.drawY,sprite.drawX+sprite.bitmap->width-1,sprite.drawY+sprite.bitmap->height-1));
+}
+
+// rect is the portion of the sprite to update. It must be entirely contained within the
+// sprite's actual, full rectangle.
void Graphics::drawSprite(const Sprite &sprite, const Common::Rect &rect) {
- int drawWidth = rect.right - rect.left;
- int drawHeight = rect.bottom - rect.top;
+ Common::Rect spriteRect = Common::Rect(sprite.drawX, sprite.drawY,
+ sprite.drawX+sprite.bitmap->width-1, sprite.drawY+sprite.bitmap->height-1);
- if (drawWidth <= 0 || drawHeight <= 0)
- error("drawSprite: w/h <= 0");
-
+ assert(_screenRect.contains(rect));
+ assert(spriteRect.contains(rect));
byte *dest = _canvas->pixels + rect.top*SCREEN_WIDTH + rect.left;
- int canvasOffsetToNextLine = SCREEN_WIDTH - drawWidth;
switch(sprite.drawMode) {
case 0: { // Normal sprite
byte *src = sprite.bitmap->pixels + (rect.left - sprite.drawX)
+ (rect.top - sprite.drawY) * sprite.bitmap->width;
- int spriteOffsetToNextLine = sprite.bitmap->width - drawWidth;
int priOffset = rect.top*SCREEN_WIDTH + rect.left;
for (int y=rect.top; y<rect.bottom; y++) {
for (int x=rect.left; x<rect.right; x++) {
byte priByte = _priData[priOffset/2];
- byte bgPri;
+ byte bgPriority;
if ((priOffset%2) == 1)
- bgPri = (priByte)&0xf;
+ bgPriority = priByte&0xf;
else
- bgPri = (priByte)>>4;
+ bgPriority = priByte>>4;
priOffset++;
byte b = *src++;
- if (b == 0 || sprite.drawPriority < bgPri) {
+ if (b == 0 || sprite.drawPriority < bgPriority) {
dest++;
continue;
}
*dest++ = b;
}
- src += spriteOffsetToNextLine;
- dest += canvasOffsetToNextLine;
- priOffset += canvasOffsetToNextLine;
+ src += sprite.bitmap->width - rect.width();
+ dest += SCREEN_WIDTH - rect.width();
+ priOffset += SCREEN_WIDTH - rect.width();
+ }
+ break;
+ }
+
+ case 1: // Invisible
+ break;
+
+ case 2: { // Normal sprite with darkened background for "transparent" pixels (and no priority)
+ byte *src = sprite.bitmap->pixels + (rect.left - sprite.drawX)
+ + (rect.top - sprite.drawY) * sprite.bitmap->width;
+
+ for (int y=rect.top; y<rect.bottom; y++) {
+ for (int x=rect.left; x<rect.right; x++) {
+ byte b = *src;
+
+ if (b == 0) // Transparent (darken the pixel)
+ *dest = _lutData[*dest];
+ else // Solid color
+ *dest = b;
+
+ src++;
+ dest++;
+ }
+
+ src += sprite.bitmap->width - rect.width();
+ dest += SCREEN_WIDTH - rect.width();
+ }
+
+ break;
+ }
+
+ case 3: { // Text
+ // The sprite's "bitmap" is not actually a bitmap, but instead the list of
+ // characters to display.
+
+ Common::Rect rectangle1;
+
+ rectangle1.left = (rect.left - sprite.drawX)/8;
+ rectangle1.top = (rect.top - sprite.drawY)/8;
+ rectangle1.right = (rect.right - sprite.drawX)/8;
+ rectangle1.bottom = (rect.bottom - sprite.drawY)/8;
+
+ int drawWidth = rectangle1.width() + 1;
+ int drawHeight = rectangle1.height() + 1;
+
+ dest =_canvas->pixels + sprite.drawY*SCREEN_WIDTH + sprite.drawX
+ + rectangle1.top*8*SCREEN_WIDTH + rectangle1.left*8;
+
+ byte *src = sprite.bitmap->pixels + rectangle1.top*sprite.bitmap->width/8 + rectangle1.left;
+
+ for (int y=0; y<drawHeight; y++) {
+ for (int x=0; x<drawWidth; x++) {
+ byte c = *src;
+
+ int textColor;
+ if (c >= 0x10 && c <= 0x1A) // Border characters
+ textColor = 0xb3;
+ else
+ textColor = sprite.textColor;
+
+ byte *fontData = _font->getCharData(c);
+
+ for (int i=0;i<8;i++) {
+ for (int j=0;j<8;j++) {
+ byte b = *fontData;
+
+ if (b == 0) // Transparent: use lookup table to darken this pixel
+ *dest = _lutData[*dest];
+ else if (b == 0x78) // Inner part of character
+ *dest = textColor;
+ else // Outline of character
+ *dest = b;
+
+ fontData++;
+ dest++;
+ }
+ dest += SCREEN_WIDTH - 8;
+ }
+
+ dest -= (SCREEN_WIDTH*8 - 8);
+ src++;
+ }
+
+ src += sprite.bitmap->width/8 - drawWidth;
+ dest += SCREEN_WIDTH*8 - drawWidth*8;
+
}
+
break;
}
- case 1:
- case 2:
- case 3:
default:
- error("drawSprite: draw mode %d not implemented", sprite.drawMode);
+ error("drawSprite: draw mode %d invalid", sprite.drawMode);
break;
}
}
@@ -185,7 +279,7 @@ void Graphics::loadEGAData(const char *filename) {
return;
if (!_egaData)
- _egaData = (byte *)malloc(256);
+ _egaData = new byte[256];
Common::SeekableReadStream *egaStream = _vm->openFile(filename);
egaStream->read(_egaData, 256);
@@ -208,7 +302,7 @@ void Graphics::drawBackgroundImage(const char *filename) {
uint16 width = imageStream->readUint16LE();
uint16 height = imageStream->readUint16LE();
- byte *pixels = (byte *)malloc(width * height);
+ byte *pixels = new byte[width * height];
imageStream->read(pixels, width * height);
_vm->_system->getPaletteManager()->setPalette(palette, 0, 256);