1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/memstream.h"
24 #include "common/system.h"
25 
26 #include "graphics/palette.h"
27 
28 #include "draci/draci.h"
29 #include "draci/screen.h"
30 #include "draci/surface.h"
31 #include "draci/sprite.h"
32 
33 
34 namespace Draci {
35 
Screen(DraciEngine * vm)36 Screen::Screen(DraciEngine *vm) : _vm(vm) {
37 	_surface = new Surface(kScreenWidth, kScreenHeight);
38 	_palette = new byte[3 * kNumColors];
39 	_blackPalette = new byte[3 * kNumColors];
40 	for (int i = 0; i < 3 * kNumColors; ++i) {
41 		_blackPalette[i] = 0;
42 	}
43 	setPalette(NULL, 0, kNumColors);
44 	this->clearScreen();
45 }
46 
~Screen()47 Screen::~Screen() {
48 	delete _surface;
49 	delete[] _palette;
50 	delete[] _blackPalette;
51 }
52 
53 /**
54  * @brief Sets a part of the palette
55  * @param data Pointer to a buffer containing new palette data
56  *        start Index of the color where replacement should start
57  *        num Number of colors to replace
58  */
setPalette(const byte * data,uint16 start,uint16 num)59 void Screen::setPalette(const byte *data, uint16 start, uint16 num) {
60 	Common::MemoryReadStream pal(data ? data : _blackPalette, 3 * kNumColors);
61 	pal.seek(start * 3);
62 
63 	// Copy the palette
64 	for (uint16 i = start; i < start + num; ++i) {
65 		_palette[i * 3] = pal.readByte();
66 		_palette[i * 3 + 1] = pal.readByte();
67 		_palette[i * 3 + 2] = pal.readByte();
68 	}
69 
70 	// Shift the palette two bits to the left to make it brighter.  The
71 	// original game only uses 6-bit colors 0..63.
72 	for (int i = start * 3; i < (start + num) * 3; ++i) {
73 		_palette[i] <<= 2;
74 	}
75 
76 	_vm->_system->getPaletteManager()->setPalette(_palette, start, num);
77 }
78 
interpolatePalettes(const byte * first,const byte * second,uint16 start,uint16 num,int index,int number)79 void Screen::interpolatePalettes(const byte *first, const byte *second, uint16 start, uint16 num, int index, int number) {
80 	Common::MemoryReadStream firstPal(first ? first : _blackPalette, 3 * kNumColors);
81 	Common::MemoryReadStream secondPal(second ? second : _blackPalette, 3 * kNumColors);
82 	firstPal.seek(start * 3);
83 	secondPal.seek(start * 3);
84 
85 	// Interpolate the palettes
86 	for (uint16 i = start; i < start + num; ++i) {
87 		_palette[i * 3] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
88 		_palette[i * 3 + 1] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
89 		_palette[i * 3 + 2] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
90 	}
91 
92 	// Shift the palette two bits to the left to make it brighter
93 	for (int i = start * 3; i < (start + num) * 3; ++i) {
94 		_palette[i] <<= 2;
95 	}
96 
97 	_vm->_system->getPaletteManager()->setPalette(_palette, start, num);
98 }
99 
interpolate(int first,int second,int index,int number)100 int Screen::interpolate(int first, int second, int index, int number) {
101 	return (second * index + first * (number - index)) / number;
102 }
103 
104 /**
105  * @brief Copies the current memory screen buffer to the real screen
106  */
copyToScreen()107 void Screen::copyToScreen() {
108 	const Common::List<Common::Rect> *dirtyRects = _surface->getDirtyRects();
109 	Common::List<Common::Rect>::const_iterator it;
110 
111 	// If a full update is needed, update the whole screen
112 	if (_surface->needsFullUpdate()) {
113 		byte *ptr = (byte *)_surface->getPixels();
114 
115 		_vm->_system->copyRectToScreen(ptr, kScreenWidth,
116 			0, 0, kScreenWidth, kScreenHeight);
117 	} else {
118 		// Otherwise, update only the dirty rectangles
119 
120 		for (it = dirtyRects->begin(); it != dirtyRects->end(); ++it) {
121 
122 			// Pointer to the upper left corner of the rectangle
123 			byte *ptr = (byte *)_surface->getBasePtr(it->left, it->top);
124 
125 			_vm->_system->copyRectToScreen(ptr, kScreenWidth,
126 				it->left, it->top, it->width(), it->height());
127 		}
128 	}
129 
130 	// Call the "real" updateScreen and mark the surface clean
131 	_vm->_system->updateScreen();
132 	_surface->markClean();
133 }
134 
135 /**
136  * @brief Clears the screen
137  *
138  * Clears the screen and marks the whole screen dirty.
139  */
clearScreen()140 void Screen::clearScreen() {
141 	byte *ptr = (byte *)_surface->getPixels();
142 
143 	_surface->markDirty();
144 
145 	memset(ptr, 0, kScreenWidth * kScreenHeight);
146 }
147 
148 } // End of namespace Draci
149