1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 #include "3d_def.h"
26 #include "bstone_fixed_point.h"
27
28
29 enum class ShapeDrawMode {
30 simple,
31 shaded,
32 player_weapon,
33 }; // ShapeDrawMode
34
35
36 extern const uint8_t* shadingtable;
37 extern const uint8_t* lightsource;
38
39
40 #define CLOAKED_SHAPES (1)
41
42
43 /*
44 =============================================================================
45
46 GLOBALS
47
48 =============================================================================
49 */
50
51 int maxscale;
52 int maxscaleshl2;
53 int centery;
54
55 int normalshade;
56 int normalshade_div = 1;
57 int shade_max = 1;
58
59 int16_t nsd_table[] = { 1, 6, 3, 4, 1, 2 };
60 int16_t sm_table[] = { 36, 51, 62, 63, 18, 52 };
61 uint16_t* linecmds;
62
63
SetupScaling(int maxscaleheight)64 void SetupScaling(
65 int maxscaleheight)
66 {
67 maxscaleheight /= 2; // one scaler every two pixels
68
69 maxscale = maxscaleheight - 1;
70 maxscaleshl2 = maxscale * 4;
71 normalshade = (3 * maxscale) / (4 * normalshade_div);
72 centery = viewheight / 2;
73 }
74
75
76 extern bool useBounceOffset;
77
78 int bounceOffset = 0;
79
generic_scale_shape(const int xcenter,const int shapenum,const int ref_height,const int8_t lighting,const ShapeDrawMode draw_mode)80 void generic_scale_shape(
81 const int xcenter,
82 const int shapenum,
83 const int ref_height,
84 const int8_t lighting,
85 const ShapeDrawMode draw_mode)
86 {
87 const auto is_player_weapon = (draw_mode == ShapeDrawMode::player_weapon);
88
89 if (!is_player_weapon)
90 {
91 const auto ref_half_height = ref_height / 2;
92
93 if (ref_half_height == 0)
94 {
95 return;
96 }
97
98 if (ref_half_height > ::maxscaleshl2)
99 {
100 return;
101 }
102 }
103
104 const auto height =
105 is_player_weapon ?
106 (::vga_height * ref_height) / ::vga_ref_height :
107 ref_height / 4;
108
109 if (height == 0)
110 {
111 return;
112 }
113
114
115 constexpr auto side = bstone::Sprite::side;
116
117 constexpr int mid_bob = 6;
118 constexpr auto bob_start = 6;
119
120 const auto use_bobbing = is_player_weapon && useBounceOffset;
121
122 const auto bounce_offset_n =
123 use_bobbing ?
124 bounceOffset / 0x10000 :
125 0;
126
127 const auto bob_offset =
128 use_bobbing ?
129 (::vga_height * (bob_start + mid_bob - bounce_offset_n)) / ::vga_ref_height :
130 0;
131
132
133 const auto sprite_ptr = ::vid_sprite_cache.cache(
134 shapenum);
135
136 const auto sprite_width = sprite_ptr->get_width();
137 const auto sprite_height = sprite_ptr->get_height();
138
139 const auto half_height = height / 2;
140
141 const auto offset_x =
142 is_player_weapon ?
143 (::viewwidth - height) / 2 :
144 xcenter - half_height;
145
146 const auto offset_y =
147 is_player_weapon ?
148 ::vga_3d_view_bottom - height + bob_offset :
149 ::vga_3d_view_top + ::centery - half_height;
150
151 const auto left = sprite_ptr->get_left();
152 auto x1 = offset_x + ((left * height) / side);
153
154 if (x1 >= ::viewwidth)
155 {
156 return;
157 }
158
159 auto x2 = x1 + ((sprite_width * height) / side);
160
161 const auto top = sprite_ptr->get_top();
162 auto y1 = offset_y + ((top * height) / side);
163
164 if (y1 >= ::vga_3d_view_bottom)
165 {
166 return;
167 }
168
169 auto y2 = y1 + ((sprite_height * height) / side);
170
171
172 const auto tx_delta = bstone::FixedPoint{side, 0} / height;
173
174 auto tx_column = bstone::FixedPoint{};
175
176 if (x1 < 0)
177 {
178 tx_column += tx_delta * (-x1);
179 x1 = 0;
180 }
181
182 if (x2 >= ::viewwidth)
183 {
184 x2 = ::viewwidth;
185 }
186
187 if (x2 <= x1)
188 {
189 return;
190 }
191
192 auto tx_row_begin = bstone::FixedPoint{};
193
194 if (y1 < ::vga_3d_view_top)
195 {
196 tx_row_begin += tx_delta * (::vga_3d_view_top - y1);
197 y1 = ::vga_3d_view_top;
198 }
199
200 if (y2 >= ::vga_3d_view_bottom)
201 {
202 y2 = ::vga_3d_view_bottom - 1;
203 }
204
205 if (y2 <= y1)
206 {
207 return;
208 }
209
210 const uint8_t* shading = nullptr;
211
212 if (draw_mode == ShapeDrawMode::shaded)
213 {
214 auto i = shade_max - (63 * ref_height / (::normalshade * 8)) + lighting;
215
216 if (i < 0)
217 {
218 i = 0;
219 }
220 else if (i > 63)
221 {
222 i = 63;
223 }
224
225 // BBi Don't shade cloaked shape
226 if (::cloaked_shape)
227 {
228 i = 0;
229 }
230
231 shading = &::lightsource[i * 256];
232 }
233
234
235 for (int x = x1; x < x2; ++x)
236 {
237 if (!is_player_weapon && ::wallheight[x] > ref_height)
238 {
239 tx_column += tx_delta;
240 continue;
241 }
242
243 const auto column_index = tx_column.get_int();
244 const auto column = sprite_ptr->get_column(column_index);
245 auto tx_row = tx_row_begin;
246
247 for (int y = y1; y < y2; ++y)
248 {
249 const auto row_index = tx_row.get_int();
250 const auto sprite_color = column[row_index];
251
252 if (sprite_color < 0)
253 {
254 tx_row += tx_delta;
255 continue;
256 }
257
258 const auto pixel_offset = ::vl_get_offset(0, x, y);
259 auto color_index = static_cast<uint8_t>(sprite_color);
260
261 if (draw_mode == ShapeDrawMode::shaded)
262 {
263 #if CLOAKED_SHAPES
264 if (::cloaked_shape)
265 {
266 color_index = shading[0x1000 | ::vga_memory[pixel_offset]];
267 }
268 else
269 #endif
270 {
271 color_index = shading[color_index];
272 }
273 }
274
275 ::vga_memory[pixel_offset] = color_index;
276
277 tx_row += tx_delta;
278 }
279
280 tx_column += tx_delta;
281 }
282 }
283
284 /*
285 =======================
286 =
287 = ScaleLSShape with Light sourcing
288 =
289 = Draws a compiled shape at [scale] pixels high
290 =
291 = each vertical line of the shape has a pointer to segment data:
292 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
293 = top of virtual line with segment in proper place
294 = start of segment pixel*2, used to jsl into compiled scaler
295 = <repeat>
296 =
297 = Setup for call
298 = --------------
299 = GC_MODE read mode 1, write mode 2
300 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
301 = GC_INDEX pointing at GC_BITMASK
302 =
303 =======================
304 */
ScaleLSShape(int xcenter,int shapenum,int height,int8_t lighting)305 void ScaleLSShape(
306 int xcenter,
307 int shapenum,
308 int height,
309 int8_t lighting)
310 {
311 generic_scale_shape(
312 xcenter,
313 shapenum,
314 height,
315 lighting,
316 ShapeDrawMode::shaded);
317 }
318
319 /*
320 =======================
321 =
322 = ScaleShape
323 =
324 = Draws a compiled shape at [scale] pixels high
325 =
326 = each vertical line of the shape has a pointer to segment data:
327 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
328 = top of virtual line with segment in proper place
329 = start of segment pixel*2, used to jsl into compiled scaler
330 = <repeat>
331 =
332 = Setup for call
333 = --------------
334 = GC_MODE read mode 1, write mode 2
335 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
336 = GC_INDEX pointing at GC_BITMASK
337 =
338 =======================
339 */
ScaleShape(int xcenter,int shapenum,int height)340 void ScaleShape(
341 int xcenter,
342 int shapenum,
343 int height)
344 {
345 generic_scale_shape(
346 xcenter,
347 shapenum,
348 height,
349 0,
350 ShapeDrawMode::simple);
351 }
352
353 // BBi
scale_player_weapon(const int sprite_id,const int height)354 void scale_player_weapon(
355 const int sprite_id,
356 const int height)
357 {
358 generic_scale_shape(
359 0,
360 sprite_id,
361 height,
362 0,
363 ShapeDrawMode::player_weapon);
364 }
365 // BBi
366