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