1 /*
2 LOW_LEVEL_TEXTURES.C
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (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 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Friday, August 19, 1994 2:05:54 PM
22
23 Monday, February 27, 1995 11:40:47 PM (Jason')
24 rob suggests that the PPC might not write-allocate cache lines so we might be faster if we
25 read from a location we�re about to write to. he also suggested a rowbytes of 704 instead
26 of 640 off-screen for better cache performance.
27
28 Jan 30, 2000 (Loren Petrich):
29 Added some typecasts
30 Removed some "static" declarations that conflict with "extern"
31 */
32
33 #include "cseries.h"
34 #include "preferences.h"
35 #include "textures.h"
36 #include "scottish_textures.h"
37
38 /* ---------- global state */
39
texture_random_seed()40 inline uint16 & texture_random_seed()
41 {
42 static uint16 seed = 6906;
43 return seed;
44 }
45
46 /* ---------- texture horizontal polygon */
47
48 #define HORIZONTAL_WIDTH_SHIFT 7 /* 128 (8 for 256) */
49 #define HORIZONTAL_HEIGHT_SHIFT 7 /* 128 */
50 #define HORIZONTAL_FREE_BITS (32-TRIG_SHIFT-WORLD_FRACTIONAL_BITS)
51 #define HORIZONTAL_WIDTH_DOWNSHIFT (32-HORIZONTAL_WIDTH_SHIFT)
52 #define HORIZONTAL_HEIGHT_DOWNSHIFT (32-HORIZONTAL_HEIGHT_SHIFT)
53
54 struct _horizontal_polygon_line_header
55 {
56 int32 y_downshift;
57 };
58
59 struct _horizontal_polygon_line_data
60 {
61 uint32 source_x, source_y;
62 uint32 source_dx, source_dy;
63
64 void *shading_table;
65 };
66
67 /* ---------- texture vertical polygon */
68
69 #define VERTICAL_TEXTURE_WIDTH 128
70 #define VERTICAL_TEXTURE_WIDTH_BITS 7
71 #define VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS (FIXED_FRACTIONAL_BITS-VERTICAL_TEXTURE_WIDTH_BITS)
72 #define VERTICAL_TEXTURE_ONE (1<<VERTICAL_TEXTURE_WIDTH_FRACTIONAL_BITS)
73 #define VERTICAL_TEXTURE_FREE_BITS FIXED_FRACTIONAL_BITS
74 #define VERTICAL_TEXTURE_DOWNSHIFT (32-VERTICAL_TEXTURE_WIDTH_BITS)
75
76 struct _vertical_polygon_data
77 {
78 int16 downshift;
79 int16 x0;
80 int16 width;
81
82 int16 pad;
83 };
84
85 struct _vertical_polygon_line_data
86 {
87 void *shading_table;
88 pixel8 *texture;
89 int32 texture_y, texture_dy;
90 };
91
92 /* ---------- code */
93
94 // Find the next lower power of 2, and return the exponent
NextLowerExponent(int n)95 inline int NextLowerExponent(int n)
96 {
97 int xp = 0;
98 while(n > 1) {n >>= 1; xp++;}
99 return xp;
100 }
101
102 template <typename T>
average(T fg,T bg)103 inline T average(T fg, T bg)
104 {
105 return fg;
106 }
107
108 template <>
average(pixel32 fg,pixel32 bg)109 inline pixel32 average(pixel32 fg, pixel32 bg)
110 {
111 // badly assume that the pixel format is ARGB
112 return ( ((((fg) ^ (bg)) & 0xfffefefeL) >> 1) + ((fg) & (bg)) );
113 }
114
115 template <>
average(pixel16 fg,pixel16 bg)116 inline pixel16 average(pixel16 fg, pixel16 bg)
117 {
118 // badly assume that the pixel format is 565
119 return ( ((((fg) ^ (bg)) & 0xf7deU) >> 1) + ((fg) & (bg)) );
120 }
121
122 template <typename T>
alpha_blend(T fg,T bg,pixel8 alpha,pixel32 rmask,pixel32 bmask,pixel32 gmask)123 inline T alpha_blend(T fg, T bg, pixel8 alpha, pixel32 rmask, pixel32 bmask, pixel32 gmask)
124 {
125 return (
126 (rmask & ((bg & rmask) + ((int)(1LL*((int)(fg & rmask) - (int)(bg & rmask)) * alpha) >> 8))) |
127 (gmask & ((bg & gmask) + ((int)(1LL*((int)(fg & gmask) - (int)(bg & gmask)) * alpha) >> 8))) |
128 (bmask & ((bg & bmask) + ((int)(1LL*((int)(fg & bmask) - (int)(bg & bmask)) * alpha) >> 8)))
129 );
130 }
131
132 template <typename T, int sw_alpha_blend, bool check_transparency>
write_pixel(T * dst,pixel8 pixel,T * shading_table,uint8 * opacity_table,pixel32 rmask,pixel32 gmask,pixel32 bmask)133 void inline write_pixel(T *dst, pixel8 pixel, T *shading_table, uint8 *opacity_table, pixel32 rmask, pixel32 gmask, pixel32 bmask)
134 {
135 if (!check_transparency || pixel != 0)
136 {
137 if (sw_alpha_blend == _sw_alpha_off)
138 {
139 *dst = shading_table[pixel];
140 }
141 else if (sw_alpha_blend == _sw_alpha_fast)
142 {
143 *dst = average(shading_table[pixel], *dst);
144 }
145 else if (sw_alpha_blend == _sw_alpha_nice)
146 {
147 *dst = alpha_blend(shading_table[pixel], *dst, opacity_table[pixel], rmask, gmask, bmask);
148 }
149 }
150 }
151
152 template <typename T, int sw_alpha_blend>
153 void texture_horizontal_polygon_lines
154 (
155 struct bitmap_definition *texture,
156 struct bitmap_definition *screen,
157 struct view_data *view,
158 struct _horizontal_polygon_line_data *data,
159 short y0,
160 short *x0_table,
161 short *x1_table,
162 short line_count,
163 uint8 *opacity_table = 0
164 )
165 {
166 (void) (view);
167
168 pixel32 rmask = 0;
169 pixel32 gmask = 0;
170 pixel32 bmask = 0;
171
172 if (sw_alpha_blend == _sw_alpha_nice)
173 {
174 extern SDL_Surface *world_pixels;
175 SDL_PixelFormat *fmt = world_pixels->format;
176
177 rmask = fmt->Rmask;
178 gmask = fmt->Gmask;
179 bmask = fmt->Bmask;
180 }
181
182 while ((line_count-= 1)>=0)
183 {
184 short x0= *x0_table++, x1= *x1_table++;
185
186 T *shading_table= (T *)data->shading_table;
187 T *write= (T *) screen->row_addresses[y0] + x0;
188 pixel8 *base_address= texture->row_addresses[0];
189 uint32 source_x= data->source_x;
190 uint32 source_y= data->source_y;
191 uint32 source_dx= data->source_dx;
192 uint32 source_dy= data->source_dy;
193 short count= x1-x0;
194
195 while ((count-= 1)>=0)
196 {
197 write_pixel<T, sw_alpha_blend, false>(write++, base_address[((source_y>>(HORIZONTAL_HEIGHT_DOWNSHIFT-7))&(0x7f<<7))+(source_x>>HORIZONTAL_WIDTH_DOWNSHIFT)], shading_table, opacity_table, rmask, gmask, bmask);
198
199 source_x+= source_dx, source_y+= source_dy;
200 }
201
202 data+= 1;
203 y0+= 1;
204 }
205 }
206
207 #define LANDSCAPE_WIDTH_BITS 9
208 #define LANDSCAPE_TEXTURE_WIDTH_DOWNSHIFT (32-LANDSCAPE_WIDTH_BITS)
209 template <typename T>
landscape_horizontal_polygon_lines(struct bitmap_definition * texture,struct bitmap_definition * screen,struct view_data * view,struct _horizontal_polygon_line_data * data,short y0,short * x0_table,short * x1_table,short line_count)210 void landscape_horizontal_polygon_lines(
211 struct bitmap_definition *texture,
212 struct bitmap_definition *screen,
213 struct view_data *view,
214 struct _horizontal_polygon_line_data *data,
215 short y0,
216 short *x0_table,
217 short *x1_table,
218 short line_count)
219 {
220 short landscape_texture_width_downshift= 32 - NextLowerExponent(texture->height);
221
222 (void) (view);
223
224 while ((line_count-= 1)>=0)
225 {
226 short x0= *x0_table++, x1= *x1_table++;
227
228 T *shading_table= (T *)data->shading_table;
229 T *write= (T *)screen->row_addresses[y0] + x0;
230 pixel8 *read= texture->row_addresses[data->source_y];
231 uint32 source_x= data->source_x;
232 uint32 source_dx= data->source_dx;
233 short count= x1-x0;
234
235 while ((count-= 1)>=0)
236 {
237 *write++= shading_table[read[source_x>>landscape_texture_width_downshift]];
238 source_x+= source_dx;
239 }
240
241 data+= 1;
242 y0+= 1;
243 }
244 }
245
246 template <typename T, bool check_transparent>
copy_check_transparent(T * dst,pixel8 read,T * shading_table)247 void inline copy_check_transparent(T *dst, pixel8 read, T *shading_table)
248 {
249 if (!check_transparent || read != 0)
250 {
251 *dst = shading_table[read];
252 }
253 }
254
255
256 template <typename T, int sw_alpha_blend, bool check_transparent>
257 void texture_vertical_polygon_lines(
258 struct bitmap_definition *screen,
259 struct view_data *view,
260 struct _vertical_polygon_data *data,
261 short *y0_table,
262 short *y1_table,
263 uint8 *opacity_table = 0)
264 {
265 struct _vertical_polygon_line_data *line= (struct _vertical_polygon_line_data *) (data+1);
266 int bytes_per_row= screen->bytes_per_row;
267 int downshift= data->downshift;
268 int line_count= data->width;
269 bool aborted= false;
270 int x= data->x0;
271 int count;
272
273 (void) (view);
274
275 pixel32 rmask = 0;
276 pixel32 gmask = 0;
277 pixel32 bmask = 0;
278
279 if (sw_alpha_blend == _sw_alpha_nice) {
280 extern SDL_Surface *world_pixels;
281 SDL_PixelFormat *fmt = world_pixels->format;
282
283 rmask = fmt->Rmask;
284 gmask = fmt->Gmask;
285 bmask = fmt->Bmask;
286 }
287
288 while (line_count>0)
289 {
290 if (line_count<4 || (x&3) || aborted)
291 {
292 int y0= *y0_table++, y1= *y1_table++;
293 uint32 texture_y= line->texture_y;
294 uint32 texture_dy= line->texture_dy;
295 T *write, *shading_table;
296 pixel8 *read;
297
298 shading_table= (T *)line->shading_table;
299 read= line->texture;
300 write= (T *)screen->row_addresses[y0] + x;
301
302 for (count= y1-y0; count>0; --count)
303 {
304 write_pixel<T, sw_alpha_blend, check_transparent>(write, read[texture_y>>downshift], shading_table, opacity_table, rmask, gmask, bmask);
305
306 write = (T *)((byte *)write + bytes_per_row);
307 texture_y+= texture_dy;
308 }
309
310 x+= 1;
311 line+= 1;
312 line_count-= 1;
313
314 aborted= false;
315 }
316 else
317 {
318 uint32 texture_y0= line[0].texture_y, texture_dy0= line[0].texture_dy;
319 pixel8 *read0= line[0].texture;
320 T *shading_table0= (T *)line[0].shading_table;
321
322 uint32 texture_y1= line[1].texture_y, texture_dy1= line[1].texture_dy;
323 pixel8 *read1= line[1].texture;
324 T *shading_table1= (T *)line[1].shading_table;
325
326 uint32 texture_y2= line[2].texture_y, texture_dy2= line[2].texture_dy;
327 pixel8 *read2= line[2].texture;
328 T *shading_table2= (T *)line[2].shading_table;
329
330 uint32 texture_y3= line[3].texture_y, texture_dy3= line[3].texture_dy;
331 pixel8 *read3= line[3].texture;
332 T *shading_table3= (T *)line[3].shading_table;
333
334 T *write;
335
336 int ymax;
337
338 /* sync */
339 {
340 int y0= y0_table[0], y1= y0_table[1], y2= y0_table[2], y3= y0_table[3];
341 T *temp_write;
342
343 ymax= MAX(y0, y1), ymax= MAX(ymax, y2), ymax= MAX(ymax, y3);
344 write= (T *)screen->row_addresses[ymax] + x;
345
346 {
347 int ymin= MIN(y1_table[0], y1_table[1]);
348
349 ymin= MIN(ymin, y1_table[2]);
350 ymin= MIN(ymin, y1_table[3]);
351
352 if (ymin<=ymax)
353 {
354 aborted= true;
355 continue;
356 }
357 }
358
359 for (count= ymax-y0, temp_write= (T *)screen->row_addresses[y0] + x; count>0; --count)
360 {
361 copy_check_transparent<T, check_transparent>(temp_write, read0[texture_y0>>downshift], shading_table0);
362 temp_write = (T *)((byte *)temp_write + bytes_per_row);
363 texture_y0+= texture_dy0;
364 }
365
366 for (count= ymax-y1, temp_write= (T *)screen->row_addresses[y1] + x; count>0; --count)
367 {
368 copy_check_transparent<T, check_transparent>(temp_write + 1, read1[texture_y1>>downshift], shading_table1);
369 temp_write = (T *)((byte *)temp_write + bytes_per_row);
370 texture_y1+= texture_dy1;
371 }
372
373 for (count= ymax-y2, temp_write= (T *)screen->row_addresses[y2] + x; count>0; --count)
374 {
375 copy_check_transparent<T, check_transparent>(temp_write + 2, read2[texture_y2>>downshift], shading_table2);
376 temp_write = (T *)((byte *)temp_write + bytes_per_row);
377 texture_y2+= texture_dy2;
378 }
379
380 for (count= ymax-y3, temp_write= (T *)screen->row_addresses[y3] + x; count>0; --count)
381 {
382 copy_check_transparent<T, check_transparent>(temp_write + 3, read3[texture_y3>>downshift], shading_table3);
383 temp_write = (T *)((byte *)temp_write + bytes_per_row);
384 texture_y3+= texture_dy3;
385 }
386 }
387
388 /* parallel map (x4) */
389 {
390 int dy0= y1_table[0] - ymax;
391 int dy1= y1_table[1] - ymax;
392 int dy2= y1_table[2] - ymax;
393 int dy3= y1_table[3] - ymax;
394
395 count= MIN(dy0, dy1), count= MIN(count, dy2), count= MIN(count, dy3);
396 ymax+= count;
397
398 for (; count>0; --count)
399 {
400 write_pixel<T, sw_alpha_blend, check_transparent>(write, read0[texture_y0>>downshift], shading_table0, opacity_table, rmask, gmask, bmask);
401 texture_y0+= texture_dy0;
402
403 write_pixel<T, sw_alpha_blend, check_transparent>(write+1, read1[texture_y1>>downshift], shading_table1, opacity_table, rmask, gmask, bmask);
404 texture_y1+= texture_dy1;
405
406 write_pixel<T, sw_alpha_blend, check_transparent>(write+2, read2[texture_y2>>downshift], shading_table2, opacity_table, rmask, gmask, bmask);
407 texture_y2+= texture_dy2;
408
409 write_pixel<T, sw_alpha_blend, check_transparent>(write+3, read3[texture_y3>>downshift], shading_table3, opacity_table, rmask, gmask, bmask);
410 texture_y3+= texture_dy3;
411
412 write = (T *)((byte *)write + bytes_per_row);
413 }
414 }
415
416 /* desync */
417 {
418 T *temp_write;
419
420 for (count= y1_table[0] - ymax, temp_write= write; count>0; --count)
421 {
422 copy_check_transparent<T, check_transparent>(temp_write, read0[texture_y0>>downshift], shading_table0);
423 temp_write = (T *)((byte *)temp_write + bytes_per_row);
424 texture_y0+= texture_dy0;
425 }
426
427 for (count= y1_table[1] - ymax, temp_write= write; count>0; --count)
428 {
429 copy_check_transparent<T, check_transparent>(temp_write + 1, read1[texture_y1>>downshift], shading_table1);
430 temp_write = (T *)((byte *)temp_write + bytes_per_row);
431 texture_y1+= texture_dy1;
432 }
433
434 for (count= y1_table[2] - ymax, temp_write= write; count>0; --count)
435 {
436 copy_check_transparent<T, check_transparent>(temp_write + 2, read2[texture_y2>>downshift], shading_table2);
437 temp_write = (T *)((byte *)temp_write + bytes_per_row);
438 texture_y2+= texture_dy2;
439 }
440
441 for (count= y1_table[3] - ymax, temp_write= write; count>0; --count)
442 {
443 copy_check_transparent<T, check_transparent>(temp_write + 3, read3[texture_y3>>downshift], shading_table3);
444 temp_write = (T *)((byte *)temp_write + bytes_per_row);
445 texture_y3+= texture_dy3;
446 }
447 }
448
449 y0_table+= 4, y1_table+= 4;
450 line_count-= 4;
451 line+= 4;
452 x+= 4;
453 }
454 }
455 }
456
457 template <typename T>
tint_tables_pointer(_vertical_polygon_line_data * line,short tint_table_index)458 inline void *tint_tables_pointer(_vertical_polygon_line_data *line, short tint_table_index)
459 {
460 return 0;
461 }
462
463 template <>
464 inline void *tint_tables_pointer<pixel8>(_vertical_polygon_line_data *line, short tint_table_index)
465 {
466 return (void *) ((pixel8 *) line->shading_table + tint_table_index * sizeof(struct tint_table8));
467 }
468
469 template <>
470 inline void *tint_tables_pointer<pixel16>(_vertical_polygon_line_data *line, short tint_table_index)
471 {
472 return (void *) ((struct tint_table16 *) line->shading_table + (tint_table_index<<1));
473 }
474
475 template <>
476 inline void *tint_tables_pointer<pixel32>(_vertical_polygon_line_data *line, short tint_table_index)
477 {
478 return (void *) ((struct tint_table32 *) line->shading_table + (tint_table_index<<3));
479 }
480
481 template <typename T>
get_pixel_tint(T,void *,SDL_PixelFormat *)482 inline T get_pixel_tint(T, void *, SDL_PixelFormat *)
483 {
484 return 0;
485 }
486
487 template <>
get_pixel_tint(pixel8 pixel,void * tint_tables,SDL_PixelFormat *)488 inline pixel8 get_pixel_tint(pixel8 pixel, void *tint_tables, SDL_PixelFormat *)
489 {
490 return ((pixel8 *) tint_tables)[pixel];
491 }
492
493 template<>
get_pixel_tint(pixel16 pixel,void * tint_tables_pv,SDL_PixelFormat * fmt)494 inline pixel16 get_pixel_tint(pixel16 pixel, void *tint_tables_pv, SDL_PixelFormat *fmt)
495 {
496 tint_table16 *tint_tables = (tint_table16 *) tint_tables_pv;
497 uint8 r = (((pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss);
498 uint8 g = (((pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss);
499 uint8 b = (((pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss);
500
501 return tint_tables->red[r >> 3] | tint_tables->green[g >> 3] | tint_tables->blue[b >> 3];
502 }
503
504 template <>
get_pixel_tint(pixel32 pixel,void * tint_tables_pv,SDL_PixelFormat * fmt)505 inline pixel32 get_pixel_tint(pixel32 pixel, void *tint_tables_pv, SDL_PixelFormat *fmt)
506 {
507 tint_table32 *tint_tables = (tint_table32 *) tint_tables_pv;
508 uint8 r = (((pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss);
509 uint8 g = (((pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss);
510 uint8 b = (((pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss);
511
512 return tint_tables->red[r] | tint_tables->green[g] | tint_tables->blue[b];
513 }
514
515 template <typename T>
tint_vertical_polygon_lines(struct bitmap_definition * screen,struct view_data * view,struct _vertical_polygon_data * data,short * y0_table,short * y1_table,uint16 transfer_data)516 void tint_vertical_polygon_lines(
517 struct bitmap_definition *screen,
518 struct view_data *view,
519 struct _vertical_polygon_data *data,
520 short *y0_table,
521 short *y1_table,
522 uint16 transfer_data)
523 {
524 short tint_table_index= transfer_data&0xff;
525 struct _vertical_polygon_line_data *line= (struct _vertical_polygon_line_data *) (data+1);
526 short bytes_per_row= screen->bytes_per_row;
527 int line_count= data->width;
528 int x= data->x0;
529
530 void *tint_tables = tint_tables_pointer<T>(line, tint_table_index);
531
532 (void) (view);
533
534 extern SDL_Surface *world_pixels;
535
536 fc_assert(tint_table_index>=0 && tint_table_index<number_of_shading_tables);
537
538 while ((line_count-= 1)>=0)
539 {
540 short y0= *y0_table++, y1= *y1_table++;
541 T *write= (T *) screen->row_addresses[y0] + x;
542 pixel8 *read= line->texture;
543 _fixed texture_y= line->texture_y, texture_dy= line->texture_dy;
544 short count= y1-y0;
545
546 while ((count-=1)>=0)
547 {
548 if (read[FIXED_INTEGERAL_PART(texture_y)])
549 {
550 *write = get_pixel_tint<T>(*write, tint_tables, world_pixels->format);
551
552 }
553
554 write = (T *)((byte *)write + bytes_per_row);
555 texture_y+= texture_dy;
556 }
557
558 line+= 1;
559 x+= 1;
560 }
561 }
562
563
564 template <typename T>
randomize_vertical_polygon_lines_write(uint16 seed)565 inline T randomize_vertical_polygon_lines_write(uint16 seed)
566 {
567 return static_cast<T>(seed);
568 }
569
570 template <>
571 inline pixel32 randomize_vertical_polygon_lines_write<pixel32>(uint16 seed)
572 {
573 return (pixel32)seed^(((pixel32)seed)<<8);
574 }
575
576 template <typename T, bool check_transparent>
randomize_vertical_polygon_lines(struct bitmap_definition * screen,struct view_data * view,struct _vertical_polygon_data * data,short * y0_table,short * y1_table,uint16 transfer_data)577 void randomize_vertical_polygon_lines(
578 struct bitmap_definition *screen,
579 struct view_data *view,
580 struct _vertical_polygon_data *data,
581 short *y0_table,
582 short *y1_table,
583 uint16 transfer_data)
584 {
585 struct _vertical_polygon_line_data *line= (struct _vertical_polygon_line_data *) (data+1);
586 short bytes_per_row= screen->bytes_per_row;
587 int line_count= data->width;
588 int x= data->x0;
589 uint16 seed= texture_random_seed();
590 uint16 drop_less_than= transfer_data;
591
592 (void) (view);
593
594 while ((line_count-= 1)>=0)
595 {
596 short y0= *y0_table++, y1= *y1_table++;
597 T *write= (T *) screen->row_addresses[y0] + x;
598 pixel8 *read= line->texture;
599 _fixed texture_y= line->texture_y, texture_dy= line->texture_dy;
600 short count= y1-y0;
601
602 while ((count-=1)>=0)
603 {
604 if (!check_transparent || read[texture_y>>(data->downshift)])
605 {
606 if (seed >= drop_less_than) *write = randomize_vertical_polygon_lines_write<T>(seed);
607 if (seed&1) seed= (seed>>1)^0xb400; else seed= seed>>1;
608 }
609
610 write = (T *)((byte *)write + bytes_per_row);
611 texture_y+= texture_dy;
612 }
613
614 line+= 1;
615 x+= 1;
616 }
617
618 texture_random_seed() = seed;
619 }
620