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 "ags/engine/ac/walk_behind.h"
24 #include "ags/shared/ac/common.h"
25 #include "ags/shared/ac/common_defines.h"
26 #include "ags/engine/ac/game_state.h"
27 #include "ags/engine/gfx/graphics_driver.h"
28 #include "ags/shared/gfx/bitmap.h"
29 #include "ags/globals.h"
30 
31 namespace AGS3 {
32 
33 using namespace AGS::Shared;
34 using namespace AGS::Engine;
35 
update_walk_behind_images()36 void update_walk_behind_images() {
37 	int ee, rr;
38 	int bpp = (_GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic->GetColorDepth() + 7) / 8;
39 	Bitmap *wbbmp;
40 	for (ee = 1; ee < MAX_WALK_BEHINDS; ee++) {
41 		update_polled_stuff_if_runtime();
42 
43 		if (_G(walkBehindRight)[ee] > 0) {
44 			wbbmp = BitmapHelper::CreateTransparentBitmap(
45 			            (_G(walkBehindRight)[ee] - _G(walkBehindLeft)[ee]) + 1,
46 			            (_G(walkBehindBottom)[ee] - _G(walkBehindTop)[ee]) + 1,
47 			            _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic->GetColorDepth());
48 			int yy, startX = _G(walkBehindLeft)[ee], startY = _G(walkBehindTop)[ee];
49 			for (rr = startX; rr <= _G(walkBehindRight)[ee]; rr++) {
50 				for (yy = startY; yy <= _G(walkBehindBottom)[ee]; yy++) {
51 					if (_GP(thisroom).WalkBehindMask->GetScanLine(yy)[rr] == ee) {
52 						for (int ii = 0; ii < bpp; ii++)
53 							wbbmp->GetScanLineForWriting(yy - startY)[(rr - startX) * bpp + ii] = _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic->GetScanLine(yy)[rr * bpp + ii];
54 					}
55 				}
56 			}
57 
58 			update_polled_stuff_if_runtime();
59 
60 			if (_G(walkBehindBitmap)[ee] != nullptr) {
61 				_G(gfxDriver)->DestroyDDB(_G(walkBehindBitmap)[ee]);
62 			}
63 			_G(walkBehindBitmap)[ee] = _G(gfxDriver)->CreateDDBFromBitmap(wbbmp, false);
64 			delete wbbmp;
65 		}
66 	}
67 
68 	_G(walkBehindsCachedForBgNum) = _GP(play).bg_frame;
69 }
70 
71 
recache_walk_behinds()72 void recache_walk_behinds() {
73 	if (_G(walkBehindExists)) {
74 		free(_G(walkBehindExists));
75 		free(_G(walkBehindStartY));
76 		free(_G(walkBehindEndY));
77 	}
78 
79 	_G(walkBehindExists) = (char *)malloc(_GP(thisroom).WalkBehindMask->GetWidth());
80 	_G(walkBehindStartY) = (int *)malloc(_GP(thisroom).WalkBehindMask->GetWidth() * sizeof(int));
81 	_G(walkBehindEndY) = (int *)malloc(_GP(thisroom).WalkBehindMask->GetWidth() * sizeof(int));
82 	_G(noWalkBehindsAtAll) = 1;
83 
84 	int ee, rr, tmm;
85 	const int NO_WALK_BEHIND = 100000;
86 	for (ee = 0; ee < MAX_WALK_BEHINDS; ee++) {
87 		_G(walkBehindLeft)[ee] = NO_WALK_BEHIND;
88 		_G(walkBehindTop)[ee] = NO_WALK_BEHIND;
89 		_G(walkBehindRight)[ee] = 0;
90 		_G(walkBehindBottom)[ee] = 0;
91 
92 		if (_G(walkBehindBitmap)[ee] != nullptr) {
93 			_G(gfxDriver)->DestroyDDB(_G(walkBehindBitmap)[ee]);
94 			_G(walkBehindBitmap)[ee] = nullptr;
95 		}
96 	}
97 
98 	update_polled_stuff_if_runtime();
99 
100 	for (ee = 0; ee < _GP(thisroom).WalkBehindMask->GetWidth(); ee++) {
101 		_G(walkBehindExists)[ee] = 0;
102 		for (rr = 0; rr < _GP(thisroom).WalkBehindMask->GetHeight(); rr++) {
103 			tmm = _GP(thisroom).WalkBehindMask->GetScanLine(rr)[ee];
104 			//tmm = _getpixel(_GP(thisroom).WalkBehindMask,ee,rr);
105 			if ((tmm >= 1) && (tmm < MAX_WALK_BEHINDS)) {
106 				if (!_G(walkBehindExists)[ee]) {
107 					_G(walkBehindStartY)[ee] = rr;
108 					_G(walkBehindExists)[ee] = tmm;
109 					_G(noWalkBehindsAtAll) = 0;
110 				}
111 				_G(walkBehindEndY)[ee] = rr + 1;  // +1 to allow bottom line of screen to work
112 
113 				if (ee < _G(walkBehindLeft)[tmm]) _G(walkBehindLeft)[tmm] = ee;
114 				if (rr < _G(walkBehindTop)[tmm]) _G(walkBehindTop)[tmm] = rr;
115 				if (ee > _G(walkBehindRight)[tmm]) _G(walkBehindRight)[tmm] = ee;
116 				if (rr > _G(walkBehindBottom)[tmm]) _G(walkBehindBottom)[tmm] = rr;
117 			}
118 		}
119 	}
120 
121 	if (_G(walkBehindMethod) == DrawAsSeparateSprite) {
122 		update_walk_behind_images();
123 	}
124 }
125 
126 } // namespace AGS3
127