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 "titanic/support/video_surface.h"
24 #include "titanic/support/image_decoders.h"
25 #include "titanic/support/screen_manager.h"
26 #include "titanic/support/transparency_surface.h"
27 #include "titanic/titanic.h"
28 
29 namespace Titanic {
30 
31 int CVideoSurface::_videoSurfaceCounter = 0;
32 byte CVideoSurface::_palette1[32][32];
33 byte CVideoSurface::_palette2[32][32];
34 
CVideoSurface(CScreenManager * screenManager)35 CVideoSurface::CVideoSurface(CScreenManager *screenManager) :
36 		_screenManager(screenManager), _rawSurface(nullptr), _movie(nullptr),
37 		_pendingLoad(false), _flipVertically(false), _fastBlitFlag(false),
38 		_transparencySurface(nullptr), _transparencyMode(TRANS_DEFAULT),
39 		_freeTransparencySurface(DisposeAfterUse::NO), _hasFrame(true), _lockCount(0) {
40 	_videoSurfaceNum = _videoSurfaceCounter++;
41 }
42 
~CVideoSurface()43 CVideoSurface::~CVideoSurface() {
44 	--_videoSurfaceCounter;
45 
46 	if (_freeTransparencySurface == DisposeAfterUse::YES)
47 		delete _transparencySurface;
48 }
49 
setupPalette(byte palette[32][32],byte val)50 void CVideoSurface::setupPalette(byte palette[32][32], byte val) {
51 	for (uint idx1 = 0; idx1 < 32; ++idx1) {
52 		for (uint idx2 = 0, base = 0; idx2 < 32; ++idx2, base += idx1) {
53 			uint v = base / 31;
54 			palette[idx1][idx2] = (byte)v;
55 
56 			if (val != 0xff && v != idx2) {
57 				assert(0);
58 			}
59 		}
60 	}
61 }
62 
setSurface(CScreenManager * screenManager,DirectDrawSurface * surface)63 void CVideoSurface::setSurface(CScreenManager *screenManager, DirectDrawSurface *surface) {
64 	_screenManager = screenManager;
65 	_ddSurface = surface;
66 }
67 
blitFrom(const Point & destPos,CVideoSurface * src,const Rect * srcRect)68 void CVideoSurface::blitFrom(const Point &destPos, CVideoSurface *src, const Rect *srcRect) {
69 	if (loadIfReady() && src->loadIfReady() && _ddSurface && src->_ddSurface) {
70 		Rect srcBounds, destBounds;
71 		clipBounds(srcBounds, destBounds, src, srcRect, &destPos);
72 
73 		if (src->_flipVertically)
74 			flippedBlitRect(srcBounds, destBounds, src);
75 		else
76 			blitRect(srcBounds, destBounds, src);
77 	}
78 }
79 
blitFrom(const Point & destPos,const Graphics::Surface * src)80 void CVideoSurface::blitFrom(const Point &destPos, const Graphics::Surface *src) {
81 	lock();
82 	_rawSurface->blitFrom(*src, destPos);
83 	unlock();
84 }
85 
clipBounds(Rect & srcRect,Rect & destRect,CVideoSurface * srcSurface,const Rect * subRect,const Point * destPos)86 void CVideoSurface::clipBounds(Rect &srcRect, Rect &destRect,
87 		CVideoSurface *srcSurface, const Rect *subRect, const Point *destPos) {
88 	// Figure out initial source rect and dest rect, based on whether
89 	// specific subRect and/or destPos have been passed
90 	if (destPos) {
91 		destRect.left = destPos->x;
92 		destRect.top = destPos->y;
93 	} else {
94 		destRect.left = destRect.top = 0;
95 	}
96 
97 	if (subRect) {
98 		destRect.right = destRect.left + subRect->width();
99 		destRect.bottom = destRect.top + subRect->height();
100 		srcRect = *subRect;
101 	} else {
102 		srcRect.right = srcRect.left + srcSurface->getWidth();
103 		srcRect.bottom = srcRect.top + srcSurface->getHeight();
104 		srcRect = Rect(0, 0, srcSurface->getWidth(), srcSurface->getHeight());
105 	}
106 
107 	// Clip destination rect to be on-screen
108 	if (destRect.left < 0) {
109 		srcRect.left -= destRect.left;
110 		destRect.left = 0;
111 	}
112 	if (destRect.top < 0) {
113 		srcRect.top -= destRect.top;
114 		destRect.top = 0;
115 	}
116 	if (destRect.right > getWidth()) {
117 		srcRect.right += getWidth() - destRect.right;
118 		destRect.right = getWidth();
119 	}
120 	if (destRect.bottom > getHeight()) {
121 		srcRect.bottom += getHeight() - destRect.bottom;
122 		destRect.bottom = getHeight();
123 	}
124 
125 	// Clip source rect to be within the source surface
126 	if (srcRect.left < 0) {
127 		destRect.left -= srcRect.left;
128 		srcRect.left = 0;
129 	}
130 	if (srcRect.top < 0) {
131 		destRect.top -= srcRect.top;
132 		srcRect.top = 0;
133 	}
134 	if (srcRect.right > srcSurface->getWidth()) {
135 		destRect.right += srcSurface->getWidth() - srcRect.right;
136 		srcRect.right = srcSurface->getWidth();
137 	}
138 	if (srcRect.bottom > srcSurface->getHeight()) {
139 		destRect.bottom += srcSurface->getHeight() - srcRect.bottom;
140 		srcRect.bottom = srcSurface->getHeight();
141 	}
142 
143 	// Validate that the resulting rects are valid
144 	if (destRect.left >= destRect.right || destRect.top >= destRect.bottom
145 		|| srcRect.left >= srcRect.right || srcRect.top >= srcRect.bottom)
146 		error("Invalid rect");
147 }
148 
blitRect(const Rect & srcRect,const Rect & destRect,CVideoSurface * src)149 void CVideoSurface::blitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) {
150 	src->lock();
151 	lock();
152 
153 	if (src->_fastBlitFlag) {
154 		_rawSurface->blitFrom(*src->_rawSurface, srcRect, Point(destRect.left, destRect.top));
155 	} else if (src->getTransparencySurface()) {
156 		transBlitRect(srcRect, destRect, src, false);
157 	} else if (lock()) {
158 		if (src->lock()) {
159 			const Graphics::ManagedSurface *srcSurface = src->_rawSurface;
160 			Graphics::ManagedSurface *destSurface = _rawSurface;
161 			const uint transColor = src->getTransparencyColor();
162 
163 			destSurface->transBlitFrom(*srcSurface, srcRect, destRect, transColor);
164 
165 			src->unlock();
166 		}
167 
168 		unlock();
169 	}
170 }
171 
flippedBlitRect(const Rect & srcRect,const Rect & destRect,CVideoSurface * src)172 void CVideoSurface::flippedBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) {
173 	if (src->getTransparencySurface()) {
174 		transBlitRect(srcRect, destRect, src, true);
175 	} else if (lock()) {
176 		if (src->lock()) {
177 			Graphics::ManagedSurface *srcSurface = src->_rawSurface;
178 			Graphics::ManagedSurface *destSurface = _rawSurface;
179 			const Graphics::Surface srcArea = srcSurface->getSubArea(srcRect);
180 			const uint transColor = src->getTransparencyColor();
181 
182 			// Vertically flip the source area
183 			Graphics::ManagedSurface flippedArea(srcArea.w, srcArea.h, srcArea.format);
184 			for (int y = 0; y < srcArea.h; ++y) {
185 				const byte *pSrc = (const byte *)srcArea.getBasePtr(0, y);
186 				byte *pDest = (byte *)flippedArea.getBasePtr(0, flippedArea.h - y - 1);
187 				Common::copy(pSrc, pSrc + srcArea.pitch, pDest);
188 			}
189 
190 			destSurface->transBlitFrom(flippedArea,
191 				Common::Point(destRect.left, destRect.top), transColor);
192 
193 			src->unlock();
194 		}
195 
196 		unlock();
197 	}
198 }
199 
transBlitRect(const Rect & srcRect,const Rect & destRect,CVideoSurface * src,bool flipFlag)200 void CVideoSurface::transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src, bool flipFlag) {
201 	assert(srcRect.width() == destRect.width() && srcRect.height() == destRect.height());
202 	assert(src->getPixelDepth() == 2);
203 
204 	if (lock()) {
205 		if (src->lock()) {
206 			Graphics::ManagedSurface *srcSurface = src->_rawSurface;
207 			Graphics::ManagedSurface *destSurface = _rawSurface;
208 			Graphics::Surface destArea = destSurface->getSubArea(destRect);
209 
210 			const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr(
211 				srcRect.left, flipFlag ? srcRect.top : srcRect.bottom - 1);
212 			uint16 *destPtr = (uint16 *)destArea.getBasePtr(0, destArea.h - 1);
213 			bool isAlpha = src->_transparencyMode == TRANS_ALPHA0 ||
214 				src->_transparencyMode == TRANS_ALPHA255;
215 
216 			CTransparencySurface transSurface(src->getTransparencySurface(), src->_transparencyMode);
217 
218 			for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
219 				// Prepare for copying the line
220 				const uint16 *lineSrcP = srcPtr;
221 				uint16 *lineDestP = destPtr;
222 				transSurface.setRow(flipFlag ? srcRect.top + yCtr : srcRect.bottom - yCtr - 1);
223 				transSurface.setCol(srcRect.left);
224 
225 				for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX) {
226 					if (transSurface.isPixelOpaque())
227 						*lineDestP = *lineSrcP;
228 					else if (!transSurface.isPixelTransparent())
229 						copyPixel(lineDestP, lineSrcP, transSurface.getAlpha() >> 3, srcSurface->format, isAlpha);
230 
231 					++lineSrcP;
232 					++lineDestP;
233 					transSurface.moveX();
234 				}
235 
236 				// Move to next line
237 				srcPtr = flipFlag ? srcPtr + (src->getPitch() / 2) :
238 					srcPtr - (src->getPitch() / 2);
239 				destPtr -= destArea.pitch / 2;
240 			}
241 
242 			src->unlock();
243 		}
244 
245 		unlock();
246 	}
247 }
248 
getTransparencyColor()249 uint CVideoSurface::getTransparencyColor() {
250 	return getPixelDepth() == 2 ? 0xf81f : 0x7c1f;
251 }
252 
hasFrame()253 bool CVideoSurface::hasFrame() {
254 	if (_hasFrame) {
255 		_hasFrame = false;
256 		return true;
257 	} else if (_movie) {
258 		return _movie->hasVideoFrame();
259 	} else {
260 		return false;
261 	}
262 }
263 
264 #define RGB_SHIFT 3
copyPixel(uint16 * destP,const uint16 * srcP,byte alpha,const Graphics::PixelFormat & srcFormat,bool isAlpha)265 void CVideoSurface::copyPixel(uint16 *destP, const uint16 *srcP, byte alpha,
266 		const Graphics::PixelFormat &srcFormat, bool isAlpha) {
267 	const Graphics::PixelFormat destFormat = _ddSurface->getFormat();
268 	alpha &= 0xff;
269 	assert(alpha < 32);
270 
271 	// Get the source color
272 	byte r, g, b;
273 	srcFormat.colorToRGB(*srcP, r, g, b);
274 	r >>= RGB_SHIFT;
275 	g >>= RGB_SHIFT;
276 	b >>= RGB_SHIFT;
277 
278 	if (isAlpha) {
279 		r = _palette1[31 - alpha][r];
280 		g = _palette1[31 - alpha][g];
281 		b = _palette1[31 - alpha][b];
282 	}
283 
284 	byte r2, g2, b2;
285 	destFormat.colorToRGB(*destP, r2, g2, b2);
286 	r2 >>= RGB_SHIFT;
287 	g2 >>= RGB_SHIFT;
288 	b2 >>= RGB_SHIFT;
289 	r2 = _palette1[alpha][r2];
290 	g2 = _palette1[alpha][g2];
291 	b2 = _palette1[alpha][b2];
292 
293 	*destP = destFormat.RGBToColor((r + r2) << RGB_SHIFT,
294 		(g + g2) << RGB_SHIFT, (b + b2) << RGB_SHIFT);
295 }
296 
297 /*------------------------------------------------------------------------*/
298 
OSVideoSurface(CScreenManager * screenManager,DirectDrawSurface * surface)299 OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface) :
300 		CVideoSurface(screenManager) {
301 	_ddSurface = surface;
302 }
303 
OSVideoSurface(CScreenManager * screenManager,const CResourceKey & key,bool pendingLoad)304 OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, const CResourceKey &key, bool pendingLoad) :
305 		CVideoSurface(screenManager) {
306 	_ddSurface = nullptr;
307 	_pendingLoad = pendingLoad;
308 
309 	if (_pendingLoad) {
310 		loadResource(key);
311 	} else {
312 		_resourceKey = key;
313 		load();
314 	}
315 }
316 
~OSVideoSurface()317 OSVideoSurface::~OSVideoSurface() {
318 	if (_ddSurface)
319 		_videoSurfaceCounter -= OSVideoSurface::freeSurface();
320 }
321 
loadResource(const CResourceKey & key)322 void OSVideoSurface::loadResource(const CResourceKey &key) {
323 	_resourceKey = key;
324 	_pendingLoad = true;
325 
326 	if (hasSurface())
327 		load();
328 }
329 
loadTarga(const CResourceKey & key)330 void OSVideoSurface::loadTarga(const CResourceKey &key) {
331 	// Decode the image
332 	CTargaDecode decoder;
333 	decoder.decode(*this, key.getString());
334 
335 	if (getPixelDepth() == 2)
336 		shiftColors();
337 
338 	_resourceKey = key;
339 
340 }
341 
loadJPEG(const CResourceKey & key)342 void OSVideoSurface::loadJPEG(const CResourceKey &key) {
343 	// Decode the image
344 	CJPEGDecode decoder;
345 	decoder.decode(*this, key.getString());
346 
347 	if (getPixelDepth() == 2)
348 		shiftColors();
349 
350 	_resourceKey = key;
351 }
352 
loadTarga(const CString & name)353 void OSVideoSurface::loadTarga(const CString &name) {
354 	CResourceKey key(name);
355 	loadTarga(key);
356 }
357 
loadMovie(const CResourceKey & key,bool destroyFlag)358 void OSVideoSurface::loadMovie(const CResourceKey &key, bool destroyFlag) {
359 	// Delete any prior movie
360 	if (_movie) {
361 		delete _movie;
362 		_movie = nullptr;
363 	}
364 
365 	// Create the new movie and load the first frame to the video surface
366 	_movie = g_vm->_movieManager.createMovie(key, this);
367 	_movie->setFrame(0);
368 
369 	// If flagged to destroy, then immediately destroy movie instance
370 	if (destroyFlag) {
371 		delete _movie;
372 		_movie = nullptr;
373 	}
374 
375 	_resourceKey = key;
376 }
377 
lock()378 bool OSVideoSurface::lock() {
379 	if (!loadIfReady())
380 		return false;
381 
382 	++_lockCount;
383 	_rawSurface = _ddSurface->lock(nullptr, 0);
384 	return true;
385 }
386 
unlock()387 void OSVideoSurface::unlock() {
388 	if (!--_lockCount) {
389 		if (_rawSurface)
390 			_ddSurface->unlock();
391 		_rawSurface = nullptr;
392 	}
393 }
394 
hasSurface()395 bool OSVideoSurface::hasSurface() {
396 	return _ddSurface != nullptr;
397 }
398 
getWidth()399 int OSVideoSurface::getWidth() {
400 	if (!loadIfReady())
401 		error("Could not load resource");
402 
403 	return _ddSurface->getWidth();
404 }
405 
getHeight()406 int OSVideoSurface::getHeight() {
407 	if (!loadIfReady())
408 		error("Could not load resource");
409 
410 	return _ddSurface->getHeight();
411 }
412 
getPitch()413 int OSVideoSurface::getPitch() {
414 	if (!loadIfReady())
415 		error("Could not load resource");
416 
417 	return _ddSurface->getPitch();
418 }
419 
getBpp()420 int OSVideoSurface::getBpp() {
421 	if (!loadIfReady())
422 		error("Could not load resource");
423 
424 	return getPixelDepth();
425 }
426 
recreate(int width,int height,int bpp)427 void OSVideoSurface::recreate(int width, int height, int bpp) {
428 	freeSurface();
429 
430 	_screenManager->resizeSurface(this, width, height, bpp);
431 	if (_ddSurface)
432 		_videoSurfaceCounter += _ddSurface->getSize();
433 }
434 
resize(int width,int height,int bpp)435 void OSVideoSurface::resize(int width, int height, int bpp) {
436 	if (!_ddSurface || _ddSurface->getWidth() != width ||
437 			_ddSurface->getHeight() != height)
438 		recreate(width, height, bpp);
439 }
440 
detachSurface()441 void OSVideoSurface::detachSurface() {
442 	_ddSurface = nullptr;
443 }
444 
getPixelDepth()445 int OSVideoSurface::getPixelDepth() {
446 	if (!loadIfReady())
447 		error("Could not load resource");
448 
449 	lock();
450 
451 	int result = _rawSurface->format.bytesPerPixel;
452 	if (result == 1)
453 		// Paletted 8-bit images don't store the color directly in the pixels
454 		result = 0;
455 
456 	unlock();
457 	return result;
458 }
459 
load()460 bool OSVideoSurface::load() {
461 	if (!_resourceKey.scanForFile())
462 		return false;
463 
464 	switch (_resourceKey.fileTypeSuffix()) {
465 	case FILETYPE_IMAGE:
466 		switch (_resourceKey.imageTypeSuffix()) {
467 		case IMAGETYPE_TARGA:
468 			loadTarga(_resourceKey);
469 			break;
470 		case IMAGETYPE_JPEG:
471 			loadJPEG(_resourceKey);
472 			break;
473 		default:
474 			break;
475 		}
476 		return true;
477 
478 	case FILETYPE_MOVIE:
479 		loadMovie(_resourceKey);
480 		return true;
481 
482 	default:
483 		return false;
484 	}
485 }
486 
getPixel(const Common::Point & pt)487 uint16 OSVideoSurface::getPixel(const Common::Point &pt) {
488 	if (!loadIfReady())
489 		return 0;
490 
491 	if (pt.x >= 0 && pt.y >= 0 && pt.x < getWidth() && pt.y < getHeight()) {
492 		if (_transparencySurface) {
493 			// WORKAROUND: Original had the setRow _flipVertically check in reverse.
494 			// Pretty sure putting it the way is below is the correct way
495 			CTransparencySurface transSurface(&_transparencySurface->rawSurface(), _transparencyMode);
496 			transSurface.setRow(_flipVertically ? getHeight() - pt.y - 1 : pt.y);
497 			transSurface.setCol(pt.x);
498 
499 			if (transSurface.isPixelTransparent())
500 				return getTransparencyColor();
501 		}
502 
503 		lock();
504 		uint16 pixel = *(uint16 *)_rawSurface->getBasePtr(pt.x, pt.y);
505 		unlock();
506 		return pixel;
507 	} else {
508 		return getTransparencyColor();
509 	}
510 }
511 
setPixel(const Point & pt,uint pixel)512 void OSVideoSurface::setPixel(const Point &pt, uint pixel) {
513 	assert(getPixelDepth() == 2);
514 
515 	uint16 *pixelP = (uint16 *)_rawSurface->getBasePtr(pt.x, pt.y);
516 	*pixelP = pixel;
517 }
518 
shiftColors()519 void OSVideoSurface::shiftColors() {
520 	if (!loadIfReady())
521 		return;
522 
523 	// Currently no further processing is needed, since for ScummVM,
524 	// we already convert 16-bit surfaces as soon as they're loaded
525 }
526 
clear()527 void OSVideoSurface::clear() {
528 	if (!loadIfReady())
529 		error("Could not load resource");
530 
531 	_ddSurface->fill(nullptr, 0);
532 }
533 
playMovie(uint flags,CGameObject * obj)534 void OSVideoSurface::playMovie(uint flags, CGameObject *obj) {
535 	if (loadIfReady() && _movie)
536 		_movie->play(flags, obj);
537 }
538 
playMovie(uint startFrame,uint endFrame,uint flags,CGameObject * obj)539 void OSVideoSurface::playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj) {
540 	if (loadIfReady() && _movie) {
541 		_movie->play(startFrame, endFrame, flags, obj);
542 		_movie->pause();
543 	}
544 }
545 
playMovie(uint startFrame,uint endFrame,uint initialFrame,uint flags,CGameObject * obj)546 void OSVideoSurface::playMovie(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) {
547 	if (loadIfReady() && _movie) {
548 		_movie->play(startFrame, endFrame, initialFrame, flags, obj);
549 	}
550 }
551 
stopMovie()552 void OSVideoSurface::stopMovie() {
553 	if (_movie)
554 		_movie->stop();
555 }
556 
setMovieFrame(uint frameNumber)557 void OSVideoSurface::setMovieFrame(uint frameNumber) {
558 	if (loadIfReady() && _movie)
559 		_movie->setFrame(frameNumber);
560 }
561 
addMovieEvent(int frameNumber,CGameObject * obj)562 void OSVideoSurface::addMovieEvent(int frameNumber, CGameObject *obj) {
563 	if (_movie)
564 		_movie->addEvent(frameNumber, obj);
565 }
566 
setMovieFrameRate(double rate)567 void OSVideoSurface::setMovieFrameRate(double rate) {
568 	if (_movie)
569 		_movie->setFrameRate(rate);
570 }
571 
getMovieRangeInfo() const572 const CMovieRangeInfoList *OSVideoSurface::getMovieRangeInfo() const {
573 	return _movie ? _movie->getMovieRangeInfo() : nullptr;
574 }
575 
flipVertically(bool needsLock)576 void OSVideoSurface::flipVertically(bool needsLock) {
577 	if (!loadIfReady() || !_flipVertically)
578 		return;
579 
580 	if (needsLock)
581 		lock();
582 
583 	byte lineBuffer[SCREEN_WIDTH * 2];
584 	int pitch = getBpp() * getWidth();
585 	assert(pitch < (SCREEN_WIDTH * 2));
586 
587 	for (int yp = 0; yp < (_rawSurface->h / 2); ++yp) {
588 		byte *line1P = (byte *)_rawSurface->getBasePtr(0, yp);
589 		byte *line2P = (byte *)_rawSurface->getBasePtr(0, _rawSurface->h - yp - 1);
590 
591 		Common::copy(line1P, line1P + pitch, lineBuffer);
592 		Common::copy(line2P, line2P + pitch, line1P);
593 		Common::copy(lineBuffer, lineBuffer + pitch, line1P);
594 	}
595 
596 	_flipVertically = false;
597 	if (needsLock)
598 		unlock();
599 }
600 
loadIfReady()601 bool OSVideoSurface::loadIfReady() {
602 	_videoSurfaceNum = _videoSurfaceCounter;
603 
604 	if (hasSurface()) {
605 		return true;
606 	} else if (_pendingLoad) {
607 		_hasFrame = true;
608 		load();
609 		return true;
610 	} else {
611 		return false;
612 	}
613 }
614 
transPixelate()615 void OSVideoSurface::transPixelate() {
616 	if (!loadIfReady())
617 		return;
618 
619 	lock();
620 	Graphics::ManagedSurface *surface = _rawSurface;
621 	uint transColor = getTransparencyColor();
622 	// TODO: Check whether color is correct
623 	uint pixelColor = surface->format.RGBToColor(0x50, 0, 0);
624 
625 	for (int yp = 0; yp < surface->h; ++yp) {
626 		uint16 *pixelsP = (uint16 *)surface->getBasePtr(0, yp);
627 		bool bitFlag = (yp % 2) == 0;
628 		int replaceCtr = yp & 3;
629 
630 		for (int xp = 0; xp < surface->w; ++xp, ++pixelsP) {
631 			if (bitFlag && *pixelsP == transColor && replaceCtr == 0)
632 				*pixelsP = pixelColor;
633 
634 			bitFlag = !bitFlag;
635 			replaceCtr = (replaceCtr + 1) & 3;
636 		}
637 	}
638 
639 	surface->markAllDirty();
640 	unlock();
641 }
642 
dupMovieTransparency() const643 Graphics::ManagedSurface *OSVideoSurface::dupMovieTransparency() const {
644 	return _movie ? _movie->duplicateTransparency() : nullptr;
645 }
646 
freeSurface()647 int OSVideoSurface::freeSurface() {
648 	if (!_ddSurface)
649 		return 0;
650 	int surfaceSize = _ddSurface->getSize();
651 
652 	delete _movie;
653 	_movie = nullptr;
654 	delete _ddSurface;
655 	_ddSurface = nullptr;
656 
657 	return surfaceSize;
658 }
659 
getBasePtr(int x,int y)660 uint16 *OSVideoSurface::getBasePtr(int x, int y) {
661 	assert(_rawSurface);
662 	return (uint16 *)_rawSurface->getBasePtr(x, y);
663 }
664 
665 } // End of namespace Titanic
666