1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/debug.h"
29 #include "engines/icb/mission.h"
30 #include "engines/icb/global_objects.h"
31 
32 namespace ICB {
33 
fx_narrow_screen(int32 & result,int32 * params)34 mcodeFunctionReturnCodes fx_narrow_screen(int32 &result, int32 *params) { return (MS->fx_narrow_screen(result, params)); }
35 
fx_generic_fade(int32 & result,int32 * params)36 mcodeFunctionReturnCodes fx_generic_fade(int32 &result, int32 *params) { return (MS->fx_generic_fade(result, params)); }
37 
fx_narrow_screen(int32 &,int32 * params)38 mcodeFunctionReturnCodes _game_session::fx_narrow_screen(int32 &, int32 *params) {
39 	/* Parameters */
40 	int32 mode = params[0];    // border mode
41 	int32 red = params[1];     // red component of cover
42 	int32 green = params[2];   // green component of cover
43 	int32 blue = params[3];    // blue component of cover
44 	int32 percent = params[4]; // 0 - 100 percentage screen to cover
45 	int32 cycles = params[5];  // number of cycles to shirnk over
46 
47 	/* Function Storage */
48 	static int32 heightStep = 0;
49 	static int32 alphaStep = 0;
50 	static int32 cycleCount = 0;
51 
52 	// Get access to the border rectangle
53 	LRECT &border = surface_manager->BorderRect();
54 
55 	// Check if there is a set loaded.  If not we want to ignore the cycles param
56 	if (!MSS.OK())
57 		cycles = 1;
58 
59 	// Calculate the fxtarget screen coverage
60 	int32 fxtarget = (480 * percent) / 200;
61 
62 	if (cycleCount == 0) {
63 		// First time through
64 
65 		// Set the border colour
66 		surface_manager->BorderRed() = (uint8)red;
67 		surface_manager->BorderGreen() = (uint8)green;
68 		surface_manager->BorderBlue() = (uint8)blue;
69 
70 		// Semi-non-persistance(ish)... If percentage is not 0 make sure we start from 0
71 		if (percent) {
72 			border.top = 0;
73 			border.bottom = SCREEN_DEPTH;
74 			surface_manager->BorderAlpha() = 0;
75 		} else
76 			surface_manager->BorderAlpha() = 255;
77 
78 		// Calculate the per cycle height step
79 		heightStep = (cycles) ? (fxtarget - border.top) / cycles : fxtarget;
80 
81 		// Calculate alpha step
82 		alphaStep = (cycles) ? 255 / cycles : 255;
83 
84 		// Check if we are fading out
85 		if (percent == 0)
86 			alphaStep = 0 - alphaStep;
87 
88 		// Mode 0 has no fade so set alpha to solid
89 		if (mode == 0) { // Solid Colour
90 			alphaStep = 0;
91 			surface_manager->BorderAlpha() = 255;
92 		}
93 
94 		if (mode == 2) { // Just Fade no shrink so set height step to 0
95 			heightStep = 0;
96 
97 			if (percent) {
98 				border.top = fxtarget;
99 				border.bottom = SCREEN_DEPTH - fxtarget;
100 			}
101 		}
102 
103 		// Set the mode
104 		surface_manager->BorderMode() = mode;
105 
106 		// Check we actually need to move the borders or fade the screen
107 		if (heightStep == 0 && alphaStep == 0)
108 			return (IR_CONT);
109 	}
110 
111 	// Check if we have reached the specified border size
112 	if (cycleCount == cycles) {
113 		cycleCount = 0;
114 
115 		if (percent) {
116 			// We are leaving the screen with borders of one sort or another
117 			// So stop blending and switch to solid borders
118 			surface_manager->BorderMode() = 0;
119 		} else {
120 			// We were removing the borders, so stop drawing them now
121 			border.top = 0;
122 			border.bottom = SCREEN_DEPTH;
123 		}
124 		return (IR_CONT);
125 	}
126 
127 	// Check we aren't going to over step the borders
128 	if (abs(fxtarget - border.top) <= abs(heightStep)) {
129 		border.bottom -= fxtarget - border.top;
130 		border.top = fxtarget;
131 	} else {
132 		// Move the borders
133 		border.top += heightStep;
134 		border.bottom -= heightStep;
135 	}
136 
137 	// Check the alpha isn't going to go too far
138 	if ((alphaStep + surface_manager->BorderAlpha()) > 255) {
139 		surface_manager->BorderAlpha() = (uint8)255;
140 	} else if ((alphaStep + surface_manager->BorderAlpha()) < 0) {
141 		surface_manager->BorderAlpha() = (uint8)0;
142 	} else {
143 		surface_manager->BorderAlpha() = (uint8)(alphaStep + surface_manager->BorderAlpha());
144 	}
145 
146 	cycleCount++;
147 
148 	return (IR_REPEAT);
149 }
150 
151 // the full monty effect, fx_generic_fade(mode (0,1,2), on/off, r, g, b, cycles)
152 // where mode is 0-brighten, 1-darken, 2-fade
153 // where on/off is equiverlant to to/from
154 
fx_generic_fade(int32 &,int32 * params)155 mcodeFunctionReturnCodes _game_session::fx_generic_fade(int32 &, int32 *params) {
156 	int32 mode = params[0];
157 	int32 onOff = params[1];
158 	int32 fromRed = params[2];
159 	int32 fromGreen = params[3];
160 	int32 fromBlue = params[4];
161 	int32 toRed = params[5];
162 	int32 toGreen = params[6];
163 	int32 toBlue = params[7];
164 	int32 cycles = params[8];
165 
166 	/* Function Storage */
167 	static int32 alphaStep = 0;
168 
169 	// Is this the first time through ?
170 	if (alphaStep == 0) {
171 		// First time through
172 		alphaStep = (cycles) ? 255 / cycles : 255;
173 
174 		// Set the colour components
175 		surface_manager->FadeFromRed() = (uint8)fromRed;
176 		surface_manager->FadeFromGreen() = (uint8)fromGreen;
177 		surface_manager->FadeFromBlue() = (uint8)fromBlue;
178 		surface_manager->FadeToRed() = (uint8)toRed;
179 		surface_manager->FadeToGreen() = (uint8)toGreen;
180 		surface_manager->FadeToBlue() = (uint8)toBlue;
181 
182 		// Set the initial alpha value
183 		if (onOff)
184 			surface_manager->FadeAlpha() = 0; // Fading in
185 		else
186 			surface_manager->FadeAlpha() = 255; // Fading out
187 
188 		// Set the fade mode
189 		surface_manager->FadeMode() = mode + 1;
190 	}
191 
192 	// Increment / Decrement the alpha value
193 	int32 newAlpha = surface_manager->FadeAlpha();
194 	if (onOff) {
195 		// Fading in
196 		newAlpha += alphaStep;
197 	} else {
198 		// Fading out
199 		newAlpha -= alphaStep;
200 	}
201 
202 	// Check the limits
203 	if (newAlpha <= 0) {
204 		// Finished fade out
205 		surface_manager->FadeMode() = 0;
206 		surface_manager->FadeAlpha() = 0;
207 		alphaStep = 0;
208 		return (IR_CONT);
209 	}
210 
211 	if (newAlpha >= 255) {
212 		// Finished fade in
213 		surface_manager->FadeAlpha() = 255;
214 		alphaStep = 0;
215 		return (IR_CONT);
216 	}
217 
218 	surface_manager->FadeAlpha() = (uint8)newAlpha;
219 
220 	return (IR_REPEAT);
221 }
222 
223 } // End of namespace ICB
224