1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: r_data.c 1564 2020-12-19 06:21:07Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: r_data.c,v $
21 // Revision 1.31 2003/05/04 04:12:54 sburke
22 // Replace memcpy with memmove, to prevent a misaligned access fault on sparc.
23 //
24 // Revision 1.30 2002/12/13 19:22:12 ssntails
25 // Fix for the Z_CheckHeap and random crashes! (I hope!)
26 //
27 // Revision 1.29 2002/01/12 12:41:05 hurdler
28 // Revision 1.28 2002/01/12 02:21:36 stroggonmeth
29 //
30 // Revision 1.27 2001/12/27 22:50:25 hurdler
31 // fix a colormap bug, add scrolling floor/ceiling in hw mode
32 //
33 // Revision 1.26 2001/08/13 22:53:40 stroggonmeth
34 // Revision 1.25 2001/03/21 18:24:39 stroggonmeth
35 // Revision 1.24 2001/03/19 18:52:01 hurdler
36 //
37 // Revision 1.23 2001/03/13 22:14:20 stroggonmeth
38 // Long time no commit. 3D floors, FraggleScript, portals, ect.
39 //
40 // Revision 1.22 2000/11/04 16:23:43 bpereira
41 //
42 // Revision 1.21 2000/11/02 17:50:09 stroggonmeth
43 // Big 3Dfloors & FraggleScript commit!!
44 //
45 // Revision 1.20 2000/10/04 16:19:23 hurdler
46 // Change all those "3dfx names" to more appropriate names
47 //
48 // Revision 1.19 2000/09/28 20:57:17 bpereira
49 //
50 // Revision 1.18 2000/08/11 12:25:23 hurdler
51 // latest changes for v1.30
52 //
53 // Revision 1.17 2000/07/01 09:23:49 bpereira
54 // Revision 1.16 2000/05/03 23:51:01 stroggonmeth
55 // Revision 1.15 2000/04/23 16:19:52 bpereira
56 // Revision 1.14 2000/04/18 17:39:39 stroggonmeth
57 //
58 // Revision 1.13 2000/04/18 12:54:58 hurdler
59 // software mode bug fixed
60 //
61 // Revision 1.12 2000/04/16 18:38:07 bpereira
62 // Revision 1.11 2000/04/15 22:12:58 stroggonmeth
63 //
64 // Revision 1.10 2000/04/13 23:47:47 stroggonmeth
65 // See logs
66 //
67 // Revision 1.9 2000/04/08 17:45:11 hurdler
68 // fix some boom stuffs
69 //
70 // Revision 1.8 2000/04/08 17:29:25 stroggonmeth
71 // Revision 1.7 2000/04/08 11:27:29 hurdler
72 // fix some boom stuffs
73 //
74 // Revision 1.6 2000/04/07 01:39:53 stroggonmeth
75 // Fixed crashing bug in Linux.
76 // Made W_ColormapNumForName search in the other direction to find newer colormaps.
77 //
78 // Revision 1.5 2000/04/06 21:06:19 stroggonmeth
79 // Optimized extra_colormap code...
80 // Added #ifdefs for older water code.
81 //
82 // Revision 1.4 2000/04/06 20:40:22 hurdler
83 // Mostly remove warnings under windows
84 //
85 // Revision 1.3 2000/04/04 00:32:47 stroggonmeth
86 // Initial Boom compatability plus few misc changes all around.
87 //
88 // Revision 1.2 2000/02/27 00:42:10 hurdler
89 // Revision 1.1.1.1 2000/02/22 20:32:32 hurdler
90 // Initial import into CVS (v1.29 pr3)
91 //
92 //
93 // DESCRIPTION:
94 // Preparation of data for rendering,
95 // generation of lookups, caching, retrieval by name.
96 //
97 //-----------------------------------------------------------------------------
98
99 #include "doomincl.h"
100 #include "p_local.h"
101 #include "p_tick.h"
102 // thinker
103 #include "p_setup.h" //levelflats
104 #include "g_game.h"
105 #include "i_video.h"
106 #include "r_local.h"
107 #include "r_sky.h"
108 #include "r_data.h"
109 #include "w_wad.h"
110 // numwadfiles
111 #include "z_zone.h"
112 #include "v_video.h" //pLocalPalette
113 #include "m_swap.h"
114
115
116 // [WDJ] debug flat
117 //#define DEBUG_FLAT
118
119 // [WDJ] Generate texture controls
120
121 // [WDJ] For y clipping to be technically correct, the pixels in the source
122 // post must be skipped. To maintain compatibility with the original doom
123 // engines, which had this bug, other engines do not skip the post pixels either.
124 // Enabling corrected_clipping will make some textures slightly different
125 // than displayed in other engines.
126 // TEKWALL1 will have two boxes in the upper left corner with this off and one
127 // box with it enabled. The differences in other textures are less noticable.
128 // This only affects software rendering, hardware rendering is correct.
129 boolean corrected_clipping = 0;
130
131
132 //
133 // Graphics.
134 // DOOM graphics for walls and sprites
135 // is stored in vertical runs of opaque pixels (posts).
136 // A column is composed of zero or more posts,
137 // a patch or sprite is composed of zero or more columns.
138 //
139
140 int firstflat, lastflat, numflats;
141 int firstpatch, lastpatch, numpatches;
142
143
144 // textures
145 int numtextures=0; // total number of textures found,
146 // size of following tables
147
148 // Array [ num_textures ], owned, Z_Malloc
149 texture_t** textures = NULL;
150
151 // [WDJ] To reduce the repeated indexing using texture id num, better locality of reference.
152 // To allow creating a texture that was not loaded from textures[].
153 // Holds all the software render information.
154 // Array [ num_textures ], owned, Z_Malloc
155 texture_render_t * texture_render = NULL;
156
157 // Array [ num_textures ], owned, Z_Malloc
158 fixed_t* textureheight; // needed for texture pegging
159
160
161 #if 0
162 int *flattranslation; // for global animation
163 #endif
164 // Array [ num_textures+1 ], owned, Z_Malloc
165 int * texturetranslation;
166
167 // needed for pre rendering
168 spritelump_t * spritelumps = NULL; // array of sprite lump values, endian swapped
169 int num_spritelump = 0; // already allocated
170 int num_free_spritelump = 0; // free for allocation
171
172 // colormap lightmaps from wad COLORMAP lump
173 lighttable_t * reg_colormaps;
174
175
176 //faB: for debugging/info purpose
177 int flatmemory;
178 int spritememory;
179 int texturememory; // all textures
180
181
182 //faB: highcolor stuff
183 // [WDJ] 2012-02-06 shared for DRAW15, DRAW16, DRAW24, DRAW32
184 union color8_u color8; // remap color index to rgb value
185 #ifdef ENABLE_DRAW8_USING_12
186 byte color12_to_8[ 0x1000 ];
187 #endif
188
189
190 // src_type : TM_row_image (pic_t), TM_column_image (patch, picture)
191 // src_data : source data
192 // bytepp : source pixel size in bytes
193 // sel_offset : offset into pixel, 0..3
194 // blank_value : pixel value that is blank space, >255 = no blank pixel value
195 // out_type : TM_patch, TM_picture, TM_column_image
196 // out_flags : in created patch
197 // CPO_blank_trim : trim blank columns
198 // out_header : temp patch header for width and offset
R_Create_Patch(unsigned int width,unsigned int height,byte src_type,byte * src_data,byte bytepp,byte sel_offset,uint16_t blank_value,byte out_type,byte out_flags,patch_t * out_header)199 byte * R_Create_Patch( unsigned int width, unsigned int height,
200 /*SRC*/ byte src_type, byte * src_data, byte bytepp, byte sel_offset, uint16_t blank_value,
201 /*DEST*/ byte out_type, byte out_flags, patch_t * out_header )
202 {
203 byte postbuf[ 1024 ];
204 unsigned int head_empty_columns = 0; // left
205 unsigned int tail_empty_columns = 0; // right
206 unsigned int mid_empty_columns = 0;
207 unsigned int count_good_columns = 0;
208 unsigned int colofs_size, head_size, wb_blocksize;
209 signed int leftoffset = 0;
210 unsigned int col, length, dest_used, max_length;
211 unsigned int row_inc, col_inc;
212 byte empty_column = 0;
213 byte out_patch_header, out_columnofs, out_post;
214 byte * wb_dest; // output, ZMalloc
215 uint32_t * colofs0 = NULL;
216 post_t * destpost = NULL;
217 byte * dest_term = NULL;
218 byte * destp;
219 byte * pb; // in postbuf
220 byte * src0, * src_end, * src ;
221
222 // Source
223 if( src_type == TM_column_image )
224 {
225 row_inc = bytepp; // row to row, along col
226 col_inc = bytepp * height; // col to col
227 }
228 else // TM_row_image
229 {
230 col_inc = bytepp; // col to col, along row
231 row_inc = bytepp * width; // row to row
232 }
233
234 out_patch_header = out_columnofs = out_post = 0;
235 switch( out_type )
236 {
237 case TM_patch:
238 out_patch_header = out_columnofs = out_post = 1;
239 break;
240 case TM_picture:
241 out_columnofs = 1;
242 break;
243 case TM_column_image:
244 default:
245 break;
246 }
247
248 // Dest
249 head_size = 0;
250 colofs_size = 0;
251 dest_used = 0;
252 if( out_patch_header )
253 {
254 head_size += 8;
255 }
256 if( out_columnofs )
257 {
258 colofs_size = width * sizeof( uint32_t ); // width * 4
259 head_size += colofs_size;
260 }
261 wb_blocksize = head_size + (width * height); // guess
262 max_length = 1024; // buffer length
263 if( out_post )
264 {
265 wb_blocksize += 4;
266 max_length = 255;
267 }
268
269 wb_dest = (byte*) Z_Malloc( wb_blocksize, PU_IN_USE, NULL );
270
271 if( out_patch_header )
272 {
273 patch_t * wb_patch = (patch_t*) wb_dest;
274 wb_patch->width = width;
275 wb_patch->height = height;
276 wb_patch->leftoffset = 0;
277 wb_patch->topoffset = 0;
278 colofs0 = & wb_patch->columnofs[0];
279 }
280 else if( out_columnofs )
281 {
282 colofs0 = (uint32_t*) wb_dest; // no header
283 }
284
285 destp = wb_dest + head_size; // posting area
286 for( col=0; col<width; col++ )
287 {
288 destpost = NULL;
289 empty_column = 1; // flag column with no-posts value
290 if( colofs0 )
291 {
292 colofs0[col] = 0; // header entry for this column
293 }
294 src = src0 = & src_data[ col * col_inc ];
295 src_end = src0 + (row_inc * (height-1)) + 1; // past last byte of column
296 while( src < src_end )
297 {
298 // traverse column
299 for( ; src < src_end ; src += row_inc )
300 {
301 if( src[sel_offset] != blank_value )
302 goto start_post; // find first non blank pixel
303 }
304 // only blanks found
305 if( empty_column ) // if no posts, then will need to fix later
306 {
307 if( count_good_columns )
308 tail_empty_columns++;
309 else
310 head_empty_columns++;
311 }
312 break;
313
314 start_post:
315 // Must be at least one pixel, because blank span found a non-blank.
316 // Enter into header
317 if( empty_column )
318 {
319 if( colofs0 )
320 {
321 colofs0[col] = destp - wb_dest; // offset within patch
322 }
323 // maintain empty column count
324 count_good_columns ++;
325 mid_empty_columns += tail_empty_columns;
326 tail_empty_columns = 0;
327 empty_column = 0;
328 }
329
330 dest_used = destp - wb_dest;
331 if( out_post )
332 {
333 unsigned int topdelta = (src - src0) / row_inc;
334 if( topdelta > 254 ) // topdelta would be too large
335 break; // skip rest of height
336
337 destpost = (post_t*) destp; // posting area
338 destpost->topdelta = topdelta;
339 dest_used += 5; // post + 2 pad + term
340 }
341
342 // traverse source column
343 length = 0;
344 pb = postbuf; // must use a buffer to convert row indexing to column indexing
345 for( ; src < src_end ; src += row_inc )
346 {
347 if(src[sel_offset] == blank_value) break; // find first blank pixel
348 if( length >= max_length ) break; // max post length
349 length++;
350 *(pb++) = src[sel_offset]; // into buffer
351 }
352 // src must point to next, not included in this post
353
354 dest_used += length;
355 if( dest_used + 8 > wb_blocksize )
356 {
357 // Will not fit in the allocation
358 // Copy to new allocation.
359 unsigned int wb2_len = dest_used + 1024; // allocation increment
360 byte * wb2 = (byte*) Z_Malloc( wb2_len, PU_IN_USE, NULL );
361 intptr_t adjustdiff = (void*) wb2 - (void*) wb_dest; // byte difference in locations
362
363 // Move data to wb2
364 memcpy( wb2, wb_dest, wb_blocksize );
365
366 // Release old allocation
367 Z_Free( wb_dest );
368 wb_dest = wb2;
369 wb_blocksize = wb2_len;
370
371 // Move ptrs to wb2
372 destp += adjustdiff;
373 if( colofs0 ) colofs0 += adjustdiff;
374 if( destpost ) destpost += adjustdiff;
375 }
376
377 // Form postbuf into a column post.
378 if( destpost )
379 {
380 destpost->length = length;
381 destp[2] = 0; // pad 0
382 destp += 3; // post pixel data
383 }
384
385 // Copy must be after allocation size check.
386 memcpy( destp, postbuf, length );
387 destp += length;
388
389 if( destpost )
390 {
391 *(destp++) = 0; // pad 0
392 // Keep ptr to term, for empty columns.
393 dest_term = destp;
394 *dest_term = 0xFF; // term, may get overwritten by next post
395 // next source colpost, adv by (length + 2 byte header + 2 extra bytes)
396 // next post overwrites previous term
397 }
398 }
399 // start new column
400 if( destpost )
401 {
402 destp ++; // skip 0xFF column termination
403 dest_used++;
404 }
405 }
406
407 if( colofs0 && dest_term && mid_empty_columns )
408 {
409 // Must fix colofs that are still 0.
410 // Point column at last 0xFF written.
411 unsigned int term_offset = dest_term - wb_dest; // offset of last 0xFF
412 for( col=0; col<width; col++ )
413 {
414 if( colofs0[col] == 0 )
415 colofs0[col] = term_offset;
416 }
417 }
418
419 if( (out_flags & CPO_blank_trim) && ((head_empty_columns + tail_empty_columns) > 0) )
420 {
421 unsigned int new_head_size = 0;
422 // trim off the empty columns
423 unsigned int trim_width = head_empty_columns + tail_empty_columns;
424 width = width - trim_width;
425
426 if( out_patch_header )
427 new_head_size += 8;
428
429 if( colofs0 ) // out_patch_header or out_columnofs
430 {
431 unsigned int new_colofs_size = width * sizeof(uint32_t); // width * 4
432 unsigned int adjustcol = colofs_size - new_colofs_size; // byte difference in colorofs locations
433 new_head_size += new_colofs_size;
434
435 if( head_empty_columns )
436 {
437 // remove head_empty_columns of colofs table
438 memmove( colofs0, & colofs0[head_empty_columns], new_colofs_size );
439 }
440
441 // Move ptrs to new positions
442 for( col=0; col<width; col++ ) // new width
443 {
444 colofs0[col] -= adjustcol;
445 }
446
447 // move data due to smaller columnofs
448 memmove( wb_dest + new_head_size, wb_dest + head_size, dest_used - head_size );
449 // colofs_size = new_colofs_size; // unnecessary
450 }
451
452 dest_used = dest_used - head_size + new_head_size;
453
454 leftoffset -= head_empty_columns;
455 if( out_patch_header )
456 {
457 // update
458 patch_t * wb_patch = (patch_t*) wb_dest;
459 wb_patch->leftoffset = leftoffset;
460 wb_patch->width = width;
461 }
462 }
463
464 // Resize if necessary
465 if( dest_used + 32 < wb_blocksize )
466 {
467 // excessive allocation
468 // Copy to new allocation.
469 byte * wb2 = (byte*) Z_Malloc( dest_used, PU_IN_USE, NULL );
470 memcpy( wb2, wb_dest, dest_used );
471 // Release old allocation
472 Z_Free( wb_dest );
473 wb_dest = wb2;
474 }
475
476 if( out_header )
477 {
478 out_header->height = height;
479 out_header->width = width;
480 out_header->leftoffset = leftoffset;
481 out_header->topoffset = 0;
482 }
483 return wb_dest;
484 }
485
486
487 // Fixed, solid, image.
488 // column_oriented : source data orientation, 0 = row x column (image), 1 = column x row (pic_t)
489 // data : source data of width x height (in rows)
R_Create_Image(unsigned int width,unsigned int height,byte column_oriented,byte * data)490 byte * R_Create_Image( unsigned int width, unsigned int height, byte column_oriented, byte * data )
491 {
492 byte postbuf[ 256 ];
493 unsigned int wb_blocksize = (width * height);
494 unsigned int col, length;
495 unsigned int row_inc, col_inc;
496 byte * pb;
497 byte * src ;
498 byte * dest;
499
500 byte * wb_image = Z_Malloc( wb_blocksize, PU_IN_USE, NULL );
501
502 if( column_oriented )
503 {
504 row_inc = 1; // row to row, along col
505 col_inc = height; // col to col
506 }
507 else
508 {
509 col_inc = 1; // col to col, along row
510 row_inc = width; // row to row
511 }
512
513 dest = wb_image; // posting area
514 for( col=0; col<width; col++ )
515 {
516 src = & data[ col * col_inc ];
517
518 // Copy column
519 pb = postbuf; // put into postbuf
520 for( ; ; src += row_inc )
521 {
522 if( pb >= & postbuf[height] ) break; // max post length
523 *(pb++) = *src;
524 }
525 length = pb - postbuf; // must be at least 1
526
527 // Form postpuf into a column post.
528 memcpy( dest, postbuf, length );
529 if( length < height )
530 {
531 memset( &dest[length], 0, height - length ) ;
532 }
533
534 dest += height;
535 }
536
537 return wb_image;
538 }
539
540
541 #if 0
542 // indexed by pic_selection_e
543 byte pic_pixel_offset_table[ 3 ] = { 0, 0, 1 };
544
545 // indexed by pic_mode_t
546 // byte per pixel
547 byte pic_bytepp_table[ 5 ] = { 1, 1, 2, 3, 4 };
548
549 typedef enum {
550 PM_PALETTE,
551 PM_INTENSITY,
552 PM_ALPHA,
553 } patch_mode_e;
554
555 byte pic_operation_table[5][3] =
556 {
557 // 255 cannot be done.
558 { // Have PALETTE
559 // Want PM_PALETTE, PM_INTENSITY, PM_ALPHA
560 0, 40, 40
561 },
562 { // Have INTENSITY
563 // Want PM_PALETTE, PM_INTENSITY, PM_ALPHA
564 255, 0, 0
565 },
566 { // Have INTENSITY_ALPHA
567 // Want PM_PALETTE, PM_INTENSITY, PM_ALPHA
568 255, 0, 1
569 },
570 { // Have RGBA24
571 // Want PM_PALETTE, PM_INTENSITY, PM_ALPHA
572 49, 48, 255
573 },
574 { // Have RGBA32
575 // Want PM_PALETTE, PM_INTENSITY, PM_ALPHA
576 49, 48, 3
577 }
578 }
579
580 // mode : patch_mode_e
581 patch_t * R_Pic_to_Patch( pic_t * pic, byte patch_mode )
582 {
583 byte picmode = pic->mode;
584 byte sel_offset = 0;
585 byte blank_value = 0;
586 byte operation = pic_operation_table[picmode][patch_mode];
587 byte bytepp = pic_bytepp_table[ picmode ];
588
589 if( operation == 255 )
590 return NULL;
591
592 if( operation <= 4 )
593 {
594 sel_offset = operation;
595 }
596 else
597 {
598 // destructive operation, put into 0 byte
599 byte * w;
600 byte * w_end = &pic->data[pic->width * pic->height]
601 for( w= &pic->data[0]; w < w_end; w += bytepp )
602 {
603 RGBA_t p;
604 switch( picmode )
605 {
606 case PALETTE:
607 p = pLocalPalette[w[0]];
608 p.s.alpha = 0;
609 break;
610 case INTENSITY:
611 p.s.red = p.s.green = p.s.blue = w[0];
612 p.s.alpha = 0;
613 break;
614 case INTENSITY_ALPHA:
615 p.s.red = p.s.green = p.s.blue = w[0];
616 p.s.alpha = w[1];
617 break;
618 case RGBA24:
619 p.s.red = w[0];
620 p.s.green = w[1];
621 p.s.blue = w[2];
622 p.s.alpha = 0;
623 break;
624 case RGBA32:
625 p = ((RGBA32_t*)w)[0];
626 break;
627 }
628 switch( patch_mode )
629 {
630 case PM_PALETTE:
631 w[0] = NearestColor(p.s.red, p.s.green, p.s.blue);
632 break;
633 case PM_INTENSITY:
634 w[0] = (p.s.red + p.s.green + p.s.blue) / 3;
635 break;
636 case PM_ALPHA:
637 w[0] = p.s.alpha;
638 break;
639 }
640 }
641 }
642
643 return R_Create_Patch( pic->width, pic->height, 1, & pic->data[0],
644 bytepp, sel_offset, blank_value );
645 }
646 #endif
647
648
649 #if 0
650 // [WDJ] This description applied to previous code. It is kept for historical
651 // reasons. We may have to restore some of this functionality, but this scheme
652 // would not work with z_zone freeing cache blocks.
653 //
654 // MAPTEXTURE_T CACHING
655 // When a texture is first needed,
656 // it counts the number of composite columns
657 // required in the texture and allocates space
658 // for a column directory and any new columns.
659 // The directory will simply point inside other patches
660 // if there is only one patch in a given column,
661 // but any columns with multiple patches
662 // will have new column_t generated.
663 //
664
665
666 #endif
667
668
669 // [WDJ] Need extra texture_render when need both picture and patch for a texture.
670 // This will not be used most of the time, but when it is needed, there
671 // is no way around it. When that happens there will likely be several textures
672 // involved, because it is triggered by how the textures are used in the wad.
673
674 #ifdef RENDER_TEXTURE_EXTRA_FULL
675 // The texture_render_t will hold a Z_Malloc, and cannot be moved nor reallocated.
676 // The array of ptrs can be realloc-ed.
677 static texture_render_t * * texture_render_extra = NULL; // array of ptr
678 static byte texture_render_extra_alloc = 0; // number allocated
679 static byte texture_render_extra_count = 0; // number used
680 #endif
681
682 // One extra texren, for all uses. Will thrash when have too many needy textures.
683 static int common_texren_texture_num = 0;
684 static unsigned int common_texren_usage_count = 0; // number of times flushed
685 static texture_render_t common_texren = { 0, 0 }; // reused
686
687 // Cannot return NULL.
R_Get_extra_texren(int texture_num,texture_render_t * base_texren,byte model)688 texture_render_t * R_Get_extra_texren( int texture_num, texture_render_t * base_texren, byte model )
689 {
690 #ifdef RENDER_TEXTURE_EXTRA_FULL
691 texture_render_t * trep;
692 int index = base_texren->extra_index; // 1..
693
694 // If existing matching texture cache entry.
695 if( index && (index <= texture_render_extra_count) && texture_render_extra )
696 {
697 // There is an existing extra.
698 trep = texture_render_extra[ index - 1 ];
699
700 if( trep->texture_model == model )
701 goto done;
702
703 // do not need more than one extra, for now.
704 }
705
706 if( texture_render_extra_count > 253 )
707 goto use_common_texren; // exceeds what can be saved as index
708
709 if( texture_render_extra_count >= texture_render_extra_alloc )
710 {
711 // Alloc the array of ptrs.
712 int new_alloc = texture_render_extra_alloc + 8;
713 void * new_array = realloc( texture_render_extra, sizeof( texture_render_t* ) * new_alloc );
714 if( new_array == NULL )
715 goto use_common_texren;
716
717 texture_render_extra = new_array;
718 texture_render_extra_alloc = new_alloc;
719 }
720
721 // Not found, create new.
722 trep = (texture_render_t*) malloc( sizeof(texture_render_t) );
723 if( trep == NULL )
724 goto use_common_texren;
725
726 texture_render_extra[ texture_render_extra_count ] = trep;
727 // link to base_texren
728 base_texren->extra_index = ++ texture_render_extra_count; // 1..
729
730 memset( trep, 0, sizeof(texture_render_t) );
731 trep->texture_model = model;
732
733 done:
734 return trep;
735
736 #endif
737
738 #ifdef RENDER_TEXTURE_EXTRA_FULL
739 use_common_texren:
740 #endif
741 // Use the common_texren for all textures.
742 // This may thrash if the wad design was sloppy.
743 if( (common_texren_texture_num != texture_num)
744 || (common_texren.texture_model != model) )
745 {
746 if( common_texren_usage_count < 0xFFFFFFFF )
747 common_texren_usage_count ++;
748 // Wrong content, so clear it.
749 if( common_texren.cache )
750 Z_Free( common_texren.cache );
751
752 }
753
754 return & common_texren; // must return something
755 }
756
757 static
R_Release_all_extra_texren(void)758 void R_Release_all_extra_texren( void )
759 {
760 if( verbose && common_texren_usage_count )
761 {
762 GenPrintf( EMSG_ver, "Common Extra texren used: %i\n", common_texren_usage_count );
763 common_texren_usage_count = 0;
764 }
765
766 #ifdef RENDER_TEXTURE_EXTRA_FULL
767 if( texture_render_extra == NULL )
768 return;
769
770 if( verbose )
771 GenPrintf( EMSG_ver, "Extra texren used: %i\n", texture_render_extra_count );
772
773 int i;
774 for( i=0; i<texture_render_extra_count; i++ )
775 {
776 texture_render_t * trep = texture_render_extra[i];
777 if( trep )
778 {
779 if( trep->cache )
780 Z_Free( trep->cache );
781 free( trep );
782 }
783 }
784
785 free( texture_render_extra );
786 texture_render_extra_alloc = texture_render_extra_count = 0;
787 #endif
788 }
789
790
791
792 #if 0
793 // Some unique Texture setup for installing a patch.
794 void R_Set_Texture_Patch( int texnum, patch_t * patch )
795 {
796 uint32_t* colofs; // to match size in wad
797
798 if( texturecache[texnum] )
799 Z_Free( texturecache[texnum] );
800
801 texturecache[texnum] = (byte*) patch;
802
803 // determine width power of 2
804 int j = 1;
805 while (j*2 <= patch->width) j<<=1;
806 texturewidthmask[texnum] = j-1;
807 textureheight[texnum] = patch->height<<FRACBITS;
808
809 colofs = &(patch->columnofs[0]);;
810 #ifdef COLOFS_PLUS_3
811 if( colofs[0] == ((patch->width * sizeof(uint32_t)) + 8) )
812 {
813 // offset to pixels instead of post header
814 // Many callers will use colofs-3 to get back to header, but
815 // some drawing functions need pixels.
816 int i;
817 for (i=0; i<patch->width; i++)
818 colofs[i] = colofs[i] + 3; // adjust colofs from wad
819 }
820 #endif
821 texturecolumnofs[texnum] = colofs;
822 }
823 #endif
824
825
826 // [WDJ] 2/5/2010
827 // See LITE96 originx=-1, LITERED originx=-4, SW1WOOD originx=-64
828 // See TEKWALL1 originy=-27, STEP2 originy=-112, and other such textures in doom wad.
829 // Patches leftoffset and topoffset are ignored when composing textures.
830
831 // The original doom has a clipping bug when originy < 0.
832 // The patch position is moved instead of clipped, the height is clipped.
833
834 //
835 // R_DrawColumnInCache
836 // Clip and draw a column from a patch into a cached post. Dest is in columns.
837 //
838
839 static
R_DrawColumnInCache(column_t * colpost,byte * cache,int originy,int cacheheight)840 void R_DrawColumnInCache ( column_t* colpost, // source, list of 0 or more post_t
841 byte* cache, // dest
842 int originy,
843 int cacheheight ) // limit
844 {
845 int count;
846 int position; // dest
847 #ifdef DEEPSEA_TALL_PATCH
848 // [MB] [WDJ] Support for DeePsea tall patches,
849 int cur_topdelta = -1;
850 #endif
851 byte* source;
852 // byte* dest;
853
854 // dest = (byte *)cache;// + 3;
855
856 // Assemble a texture from column post data from wad lump.
857 // Column is a series of posts (post_t), terminated by 0xFF
858 while (colpost->topdelta != 0xff) // end of posts
859 {
860 // post has 2 byte header (post_t),
861 // and has extra byte before and after pixel data
862 source = (byte *)colpost + 3; // pixel data after post header
863 count = colpost->length;
864
865 #ifdef DEEPSEA_TALL_PATCH
866 // When the column topdelta is <= the current topdelta,
867 // it is a DeePsea tall patch relative topdelta.
868 int topdelta = colpost->topdelta;
869 if( topdelta <= cur_topdelta )
870 {
871 // DeePsea relative topdelta
872 topdelta += cur_topdelta;
873 }
874 cur_topdelta = topdelta;
875 position = originy + topdelta; // position in dest
876 #else
877 position = originy + colpost->topdelta; // position in dest
878 #endif
879
880 if (position < 0)
881 {
882 count += position; // skip pixels off top
883 // [WDJ] For this clipping to be technically correct, the pixels
884 // in the source must be skipped too.
885 // Other engines do not skip the post pixels either, to maintain
886 // compatibility with the original doom engines, which had this bug.
887 // Enabling this will make some textures slightly different
888 // than displayed in other engines.
889 // TEKWALL1 will have two boxes in the upper left corner with this
890 // off and one box with it enabled. The differences in other
891 // textures are less noticable.
892 if( corrected_clipping )
893 {
894 source -= position; // [WDJ] 1/29/2010 skip pixels in post
895 }
896 position = 0;
897 }
898
899 if (position + count > cacheheight) // trim off bottom
900 count = cacheheight - position;
901
902 // copy column (full or partial) to dest cache at position
903 if (count > 0)
904 memcpy (cache + position, source, count);
905
906 // next source colpost, adv by (length + 2 byte header + 2 extra bytes)
907 colpost = (column_t *)( (byte *)colpost + colpost->length + 4);
908 }
909 }
910
911
912
913 //
914 // R_GenerateTexture
915 //
916 // Allocate space for full size texture, either single patch or 'composite'
917 // Build the full textures from patches.
918 // The texture caching system is a little more hungry of memory, but has
919 // been simplified for the sake of highcolor, dynamic lighting, & speed.
920 //
921 // This is not optimized, but it's supposed to be executed only once
922 // per level, when enough memory is available.
923
924 // Temp structure element used to combine patches into one dest patch.
925 typedef struct {
926 int nxt_y, bot_y; // current post segment in dest coord.
927 int width;
928 int originx, originy; // add to patch to get texture
929 #ifdef DEEPSEA_TALL_PATCH
930 // [MB] [WDJ] Support for DeePsea tall patches,
931 int cur_topdelta;
932 #endif
933 post_t * postptr; // post within that patch
934 patch_t * patch; // patch source
935 // [WDJ] Generate_Texture can now reuse columns (as done in Requiem compacted patches).
936 uint32_t usedpatchdata; // to detect reuse, compaction
937 // [WDJ] Bad patch detection
938 int patchsize;
939 } compat_t;
940
941 #ifdef DEEPSEA_TALL_PATCH
942 // [MB] [WDJ] DeePsea tall patch.
943 // DeepSea allows the patch to exceed 254 height.
944 // A Doom patch has monotonic ascending topdelta values, 0..254.
945 // DeePsea tall patches have an optional relative delta detected
946 // when col->topdelta < cur_topdelta.
947 // When the column topdelta is less than the current topdelta,
948 // it is a DeePsea tall patch relative topdelta.
949 #endif
950
951
952
953 // texnum : index into textures
954 // texture_req : requirement, TM_none, TM_masked, TM_picture, or TM_picture_column
R_GenerateTexture2(int texnum,texture_render_t * texren,byte texture_req)955 byte* R_GenerateTexture2 ( int texnum, texture_render_t * texren, byte texture_req )
956 {
957 texture_t* texture; // texture info from wad
958 texpatch_t* texpatch; // patch info to make texture
959 patch_t* realpatch; // patch lump
960 uint32_t* colofs; // to match size in wad
961
962 byte * txcblock; // allocated texture memory
963 byte * texture_end; // end of allocated texture area
964 patch_t * txcpatch; // header of txcblock
965 byte * txcdata; // posting area
966 byte * destpixels; // current post pixel in txcdata
967
968 int txcblocksize;
969
970 // array to hold all patches for combine
971 # define MAXPATCHNUM 256
972 compat_t compat[MAXPATCHNUM];
973 post_t * srcpost, * destpost;
974
975 unsigned int patchcount;
976 unsigned int compostsize;
977 byte detect_post = 0; // detect patch post incomptible with single column
978 byte detect_hole = 0;
979 byte detect = (texren->detect & TD_masked);
980 byte make_picture = 0;
981 #ifdef DEEPSEA_TALL_PATCH
982 int seg_topdelta; // current seg_topdelta
983 #endif
984 int patchsize;
985 int colofs_size;
986 int x, x1, x2, i, p;
987 int postlength; // length of current post
988 int segnxt_y, segbot_y; // may be negative
989 int bottom; // next y in column
990
991
992 texture = textures[texnum];
993 // [WDJ] Do not save GenerateTexture texture_model in the texture.
994 // There may be more than one needed, and upon reload the last
995 // generated model will appear to be a texture requirement.
996 detect |= texture->detect; // texture hints from texture load
997
998 if( texture_req == TM_none )
999 texture_req = texren->texture_model; // previous generate
1000
1001 if( texture_req == TM_picture )
1002 make_picture = 1;
1003
1004 if( texren->cache )
1005 Z_Free( texren->cache );
1006
1007 // Column offset table size as determined by wad specs.
1008 // Column pixel data starts after the table.
1009 colofs_size = texture->width * sizeof( uint32_t ); // width * 4
1010 // to allocate texture column offset lookup
1011
1012 #if 0
1013 // To debug problems with specific textures
1014 if( strncmp(texture->name, "TEKWALL5", 8 ) == 0 )
1015 debug_Printf("GenerateTexture - match\n");
1016 #endif
1017
1018 // single-patch textures can have holes and may be used on
1019 // 2sided lines so they need to be kept in 'packed' format
1020 patchcount = texture->patchcount;
1021
1022 if( patchcount >= MAXPATCHNUM )
1023 {
1024 I_SoftError("R_GenerateTexture: Patch count %i exceeds %i, ignoring rest\n",
1025 patchcount, MAXPATCHNUM);
1026 patchcount = MAXPATCHNUM - 1;
1027 }
1028
1029 // [WDJ] Protect every alloc using PU_CACHE from all Z_Malloc that
1030 // follow it, as that can deallocate the PU_CACHE unexpectedly.
1031
1032 // Texture patch format:
1033 // patch header (8 bytes), ignored
1034 // array[ texture_width ] of column offset
1035 // concatenated column posts, of variable length, terminate 0xFF
1036 // ( post header (topdelta,length), pixel data )
1037
1038 // First examination of the source patches
1039 compostsize = 0;
1040 texpatch = texture->patches;
1041 for (p=0; p<patchcount; p++, texpatch++)
1042 {
1043 compat_t * cp = &compat[p];
1044 cp->postptr = NULL; // disable until reach starting column
1045 cp->nxt_y = INT_MAX; // disable
1046
1047 // Track patch memory usage to detect reused columns.
1048 cp->usedpatchdata = 0;
1049 cp->originx = texpatch->originx;
1050 cp->originy = texpatch->originy;
1051
1052 // To avoid hardware render cache.
1053 realpatch = W_CachePatchNum_Endian(texpatch->lumpnum, PU_IN_USE); // patch temp
1054 // Preliminary characteristics of the patch.
1055 cp->patch = realpatch;
1056 cp->width = realpatch->width;
1057 int patch_colofs_size = realpatch->width * sizeof( uint32_t ); // width * 4
1058 // Need patchsize to detect invalid patches.
1059 patchsize = W_LumpLength(texpatch->lumpnum);
1060 cp->patchsize = patchsize;
1061
1062 // [WDJ] Detect PNG patches.
1063 if( ((byte*)realpatch)[0]==137
1064 && ((byte*)realpatch)[1]=='P'
1065 && ((byte*)realpatch)[2]=='N'
1066 && ((byte*)realpatch)[3]=='G' )
1067 {
1068 // Found a PNG patch, which will crash the draw8 routine.
1069 // Must assume could be used for top or bottom of wall,
1070 // which require the patch run full height (no transparent).
1071 #if 1
1072 // Enable when want to know which textures are triggering this.
1073 GenPrintf(EMSG_info,"R_GenerateTexture: Texture %8s has PNG patch.\n", texture->name );
1074 #endif
1075 goto disable_patch;
1076 }
1077
1078 // [WDJ] W_CachePatchNum should only get lumps from PATCH section,
1079 // but it will return a colormap of the same name.
1080 // Here are some validity checks, to ensure we are working with a patch.
1081 // colormap size = 0x2200 to 0x2248
1082 {
1083 uint32_t* pat_colofs = (uint32_t*)&(realpatch->columnofs); // to match size in wad
1084 if( patch_colofs_size + 8 > patchsize ) // column list exceeds patch size
1085 goto disable_patch;
1086
1087 // Look at patch columns
1088 for( i=0; i< realpatch->width; i++ )
1089 {
1090 uint32_t cofs = pat_colofs[i]; // column offset
1091 if( cofs > patchsize )
1092 goto disable_patch; // invalid column offset
1093
1094 post_t * ppp = (post_t*)( (byte*)realpatch + cofs );
1095 if( ppp->topdelta || (ppp->length != realpatch->height) )
1096 detect_post = TD_post; // patch is not single column
1097
1098 // Look for holes
1099 segbot_y = -1;
1100 #ifdef DEEPSEA_TALL_PATCH
1101 seg_topdelta = -1;
1102 #endif
1103 while( ppp->topdelta != 0xFF )
1104 {
1105 int topdelta = ppp->topdelta;
1106 #ifdef DEEPSEA_TALL_PATCH
1107 if( topdelta <= seg_topdelta )
1108 {
1109 // DeePsea relative topdelta
1110 topdelta += seg_topdelta;
1111 }
1112 seg_topdelta = topdelta;
1113 #endif
1114 if( topdelta > (segbot_y + 1) ) detect_hole = TD_hole;
1115 segbot_y = topdelta + ppp->length;
1116 ppp = (post_t*)((byte*)ppp + ppp->length + 4);
1117 }
1118 }
1119 }
1120
1121 // Add posts, without columnofs table and 8 byte patch header.
1122 compostsize += patchsize - patch_colofs_size - 8;
1123 continue;
1124
1125 disable_patch:
1126 cp->originx = 7999; // to disable this patch
1127 cp->patchsize = 0;
1128 cp->width = 0;
1129 continue;
1130 }
1131
1132 // [WDJ] When rejected PNG patches and bad patches.
1133 if( compostsize == 0 ) // no valid patches found
1134 {
1135 #if 1
1136 // Enable when want to know which textures are triggering this.
1137 GenPrintf(EMSG_info,"R_GenerateTexture: Texture %8s has no valid patches, using dummy texture.\n", texture->name );
1138 #endif
1139 goto make_dummy_texture;
1140 }
1141
1142 if( make_picture )
1143 goto multipatch_combine;
1144
1145 if( patchcount > 1 )
1146 goto multipatch_combine;
1147
1148 if( texture_req == TM_picture_column )
1149 {
1150 if( detect_hole )
1151 goto multipatch_combine;
1152 if( detect_post )
1153 goto multipatch_combine;
1154 }
1155
1156 if( patchcount==1 )
1157 {
1158 // Single patch texture, simplify
1159
1160 // [WDJ] Detect shifted origin, cannot use the simple copy.
1161 texpatch = texture->patches;
1162 if( texpatch->originx != 0 || texpatch->originy != 0 )
1163 {
1164 // [WDJ] Cannot copy patch to texture.
1165 // Fixes tekwall2, tekwall3, tekwall5 in FreeDoom,
1166 // which use right half of large combined patches.
1167 // debug_Printf("GenerateTexture %s: offset forced multipatch\n", texture->name );
1168 goto multipatch_combine;
1169 }
1170
1171 // [WDJ] Only need patch lump for the following memcpy.
1172 realpatch = compat[0].patch;
1173 patchsize = compat[0].patchsize;
1174
1175 // [WDJ] Detect mismatch of patch width, too large.
1176 if( realpatch->width > texture->width )
1177 {
1178 // [WDJ] Texture is a portion of a large patch.
1179 // To prevent duplicate large copies.
1180 // Unfortunately this also catches the large RSKY that legacy
1181 // has in legacy.wad.
1182 if( strncmp(texture->name, "SKY", 3 ) == 0 )
1183 {
1184 // let sky match patch
1185 texture->height = realpatch->height;
1186 }
1187 else
1188 {
1189 // debug_Printf("GenerateTexture %s: width forced multipatch\n", texture->name );
1190 goto multipatch_combine;
1191 }
1192 }
1193 else
1194
1195 // [WDJ] Detect mismatch of patch width, too small.
1196 if( realpatch->width < texture->width )
1197 {
1198 // [WDJ] Messy situation. Single patch texture where the patch
1199 // width is smaller than the texture. There will be segfaults when
1200 // texture columns are accessed that are not in the patch.
1201 // Rebuild the patch to meet draw expectations.
1202 // This occurs in phobiata and maybe heretic.
1203 // [WDJ] Too late to change texture size to match patch,
1204 // the caller can already be violating the patch width.
1205 // Single-sided textures need to be kept packed to preserve holes.
1206 // The texture may be rebuilt several times due to cache.
1207 int patch_colofs_size = realpatch->width * sizeof( uint32_t ); // width * 4
1208 int ofsdiff = colofs_size - patch_colofs_size;
1209 // reserve 4 bytes at end for empty post handling
1210 txcblocksize = patchsize + ofsdiff + 4;
1211 #if 0
1212 // Enable when want to know which textures are triggering this.
1213 GenPrintf(EMSG_info,"R_GenerateTexture: single patch width does not match texture width %8s\n",
1214 texture->name );
1215 #endif
1216 txcblock = Z_Malloc (txcblocksize,
1217 PU_LEVEL, // will change tag at end of this function
1218 (void**)&texren->cache);
1219
1220 // patches have 8 byte patch header, part of patch_t
1221 memcpy (txcblock, realpatch, 8); // header
1222 memcpy (txcblock + colofs_size + 8, ((byte*)realpatch) + patch_colofs_size + 8, patchsize - patch_colofs_size - 8 ); // posts
1223 // build new column offset table of texture width
1224 {
1225 // Copy patch columnofs table to texture, adjusted for new
1226 // length of columnofs table.
1227 uint32_t* pat_colofs = (uint32_t*)&(realpatch->columnofs); // to match size in wad
1228 colofs = (uint32_t*)&(((patch_t*)txcblock)->columnofs); // new
1229 for( i=0; i< realpatch->width; i++)
1230 colofs[i] = pat_colofs[i] + ofsdiff;
1231 // put empty post for all columns not in the patch.
1232 // txcblock has 4 bytes reserved for this.
1233 int empty_post = txcblocksize - 4;
1234 txcblock[empty_post] = 0xFF; // empty post list
1235 txcblock[empty_post+3] = 0xFF; // paranoid
1236 for( ; i< texture->width ; i++ )
1237 colofs[i] = empty_post;
1238 }
1239 goto single_patch_finish;
1240 }
1241
1242
1243 {
1244 // Normal: Most often use patch as it is.
1245 // texture_render cache gets copy so that PU_CACHE deallocate clears the
1246 // cache automatically
1247 txcblock = Z_Malloc (patchsize,
1248 PU_IN_USE, // will change tag at end of this function
1249 (void**)&texren->cache);
1250
1251 memcpy (txcblock, realpatch, patchsize);
1252 txcblocksize = patchsize;
1253 }
1254
1255 single_patch_finish:
1256 // Textures do not use the realpatch offsets, which may be garbage.
1257 txcpatch = (patch_t*)txcblock;
1258 txcpatch->leftoffset = 0;
1259 txcpatch->topoffset = 0;
1260
1261 // Interface for texture draw.
1262 // Use the single patch, single column lookup.
1263 colofs = (uint32_t*)&(((patch_t*)txcblock)->columnofs);
1264 // colofs from patch are relative to start of table
1265 texren->columnofs = colofs;
1266 texren->pixel_data_offset = 3; // skip over post header and pad byte
1267 texren->texture_model = TM_patch;
1268 //debug_Printf ("R_GenTex SINGLE %.8s size: %d\n",texture->name,patchsize);
1269 detect |= detect_hole | detect_post;
1270 goto done;
1271
1272 // [WDJ] Dummy texture generation.
1273 make_dummy_texture:
1274 {
1275 // make a dummy texture
1276 int head_size = colofs_size + 8;
1277 txcblocksize = head_size + 4 + texture->height + 4;
1278 // will change tag at end of this function
1279 txcblock = Z_Malloc (txcblocksize, PU_IN_USE, (void**)&texren->cache);
1280 patch_t * txcpatch = (patch_t*) txcblock;
1281 txcpatch->width = texture->width;
1282 txcpatch->height = texture->height;
1283 txcpatch->leftoffset = 0;
1284 txcpatch->topoffset = 0;
1285 destpost = (post_t*) ((byte*)txcblock + head_size); // posting area;
1286 destpost->topdelta = 0;
1287 destpost->length = texture->height;
1288 destpixels = (byte*)destpost + 3;
1289 destpixels[-1] = 0; // pad 0
1290 for( i=0; i<texture->height; i++ )
1291 {
1292 destpixels[i] = 8; // mono color
1293 }
1294 destpixels[i++] = 0; // pad 0
1295 destpixels[i] = 0xFF; // term
1296 // all columns use the same post
1297 colofs = (uint32_t*)&(txcpatch->columnofs); // has patch header
1298 for(i=0 ; i< texture->width ; i++ )
1299 colofs[i] = head_size;
1300 }
1301 goto single_patch_finish;
1302 }
1303 // End of Single-patch texture
1304
1305 multipatch_combine:
1306 // TM_combine_patch or TM_picture: Multiple patch textures.
1307 // Decide TM_ format
1308 // Combined patches + table + header
1309 compostsize += colofs_size + 8; // combined patch size
1310 txcblocksize = colofs_size + (texture->width * texture->height); // picture format size
1311
1312 if( texture_req == TM_masked )
1313 goto combine_format;
1314 if( (texture_req == TM_picture_column) && (detect_hole | detect_post) )
1315 goto picture_format;
1316 // If cache was flushed then do not change model
1317 if( texture_req == TM_picture )
1318 goto picture_format;
1319 if( texture_req == TM_combine_patch )
1320 goto combine_format;
1321 // new texture, decide on a model
1322 // if patches would not cover picture, then must have transparent regions
1323 if( compostsize < txcblocksize )
1324 goto combine_format;
1325 if( detect & TD_masked ) // hint
1326 goto combine_format;
1327 // If many patches and high overlap, then picture format is best.
1328 // This will need to be tuned if it makes mistakes.
1329 if( texture->patchcount >= 4 && compostsize > txcblocksize*4 )
1330 goto picture_format;
1331
1332 combine_format:
1333 // TM_combine_patch: Combine multiple patches into one patch.
1334
1335 // Size the new texture. It may be too big, but must not be too small.
1336 // Will usually fit into compostsize because it does so as separate patches.
1337 // Overlap of normal posts will only reduce the size.
1338 // Worst case is (width * (height/2) * (1 pixel + 4 byte overhead))
1339 // worstsize = colofs_size + 8 + (width * height * 5/2)
1340 // Usually the size will be much smaller, but it is not predictable.
1341 // all posts + new columnofs table + patch header
1342 // Compacted patches, like SW1COMM in Requiem MAP08, usually get expanded,
1343 // and they expand in the texture when they combine with other patches.
1344
1345 // [WDJ] Generate_Texture will now realloc a texture when estimate was too small.
1346 // Combined patches + table + header + 1 byte per empty column
1347 txcblocksize = compostsize + texture->width;
1348
1349 txcblock = Z_Malloc (txcblocksize, PU_IN_USE, (void**)&texren->cache);
1350 txcpatch = (patch_t*) txcblock;
1351 txcpatch->width = texture->width;
1352 txcpatch->height = texture->height;
1353 txcpatch->leftoffset = 0;
1354 txcpatch->topoffset = 0;
1355 // column offset lookup table
1356 colofs = (uint32_t*)&(txcpatch->columnofs); // has patch header
1357
1358 txcdata = (byte*)txcblock + colofs_size + 8; // posting area
1359 // starts as empty post, with 0xFF a possibility
1360 destpixels = txcdata;
1361 texture_end = txcblock + txcblocksize - 2; // do not exceed
1362 detect_post = 0; // combine has own detect
1363 detect_hole = 0;
1364
1365 // Composite the columns together.
1366 for (x=0; x<texture->width; x++)
1367 {
1368 int nxtpat; // patch number with next post
1369 int seglen, offset;
1370 // [WDJ] Detect column reuse (Requiem compacted patches).
1371 int livepatchcount = 0;
1372 int reuse_column = -1;
1373
1374 // offset to post header
1375 colofs[x] = destpixels - (byte*)txcblock; // this column
1376 destpost = (post_t*)destpixels; // first post in column
1377 postlength = 0; // length of current post
1378 bottom = 0; // next y in column
1379 segnxt_y = INT_MAX - 10; // init to very large, but less than disabled
1380 segbot_y = INT_MAX - 10;
1381 #ifdef DEEPSEA_TALL_PATCH
1382 seg_topdelta = -1; // current dest topdelta
1383 #endif
1384
1385 // setup the columns, active or inactive
1386 for (p=0; p<patchcount; p++ )
1387 {
1388 compat_t * cp = &compat[p];
1389 int patch_x = x - cp->originx; // within patch
1390 if( patch_x >= 0 && patch_x < cp->width )
1391 {
1392 realpatch = cp->patch;
1393 uint32_t* pat_colofs = (uint32_t*)&(realpatch->columnofs); // to match size in wad
1394
1395 // [WDJ] Detect bad column offset.
1396 if( pat_colofs[patch_x] > cp->patchsize ) // detect bad patch
1397 goto patch_off; // post is not within patch memory
1398
1399 cp->postptr = (post_t*)( (byte*)realpatch + pat_colofs[patch_x] ); // patch column
1400 if ( cp->postptr->topdelta == 0xFF )
1401 goto patch_off;
1402
1403 #ifdef DEEPSEA_TALL_PATCH
1404 cp->cur_topdelta = -1;
1405 #endif
1406
1407 // To handle Requiem compacted patches, where column data is reused.
1408 // Empty columns may be shared too, but they are very small,
1409 // and it really adds to logic complexity, so only look at non-empty.
1410 if ( pat_colofs[patch_x] > cp->usedpatchdata )
1411 cp->usedpatchdata = pat_colofs[patch_x]; // track normal usage pattern
1412 else
1413 {
1414 // compaction detected, look for reused column
1415 int rpx = (cp->originx < 0) ? -cp->originx : 0; // x in patch
1416 #ifdef DEBUG_REUSECOL
1417 if( DEBUG_REUSECOL )
1418 debug_Printf("GenerateTexture: %8s detected reuse of column %i in patch %i\n", texture->name, patch_x, p );
1419 #endif
1420 for( ; rpx<patch_x; rpx++ ) // find reused column
1421 {
1422 if( pat_colofs[rpx] == pat_colofs[patch_x] ) // reused in patch
1423 {
1424 int rtx = rpx + cp->originx; // x in texture
1425 #if 1
1426 // Test for reused column is from single patch
1427 int p2;
1428 int livepatchcount2 = 0;
1429 #ifdef DEBUG_REUSECOL
1430 if( DEBUG_REUSECOL )
1431 debug_Printf("GenerateTexture: testing reuse of %i, as %i\n", rpx, patch_x);
1432 #endif
1433 // [WDJ] If reused column is reused alone in both cases,
1434 // then assume they will be identical in final texture too.
1435 for (p2=0; p2<patchcount; p2++ )
1436 {
1437 compat_t * cp2 = &compat[p2];
1438 int p2_x = rtx - cp2->originx; // within patch
1439 if( p2_x >= 0 && p2_x < cp2->width )
1440 {
1441 livepatchcount2 ++;
1442 }
1443 }
1444 if ( livepatchcount2 == 1 )
1445 {
1446 reuse_column = rpx + cp->originx; // column in generated texture
1447 break;
1448 }
1449 #else
1450 // Compare with texture column, reuse when identical
1451 post_t * rpp = (post_t*)( txcblock + colofs[rtx] ); // texture column
1452 post_t * ppp = cp->postptr;
1453 #ifdef DEBUG_REUSECOL
1454 if( DEBUG_REUSECOL )
1455 debug_Printf("GenerateTexture: testing reuse of %i, as %i\n", rpx, patch_x);
1456 #endif
1457 // [WDJ] Comparision is made difficult by the pad bytes,
1458 // which we set to 0, and Requiem.wad does not.
1459 while (rpp->topdelta != 0xff) // find column end
1460 {
1461 int len = rpp->length;
1462 if( rpp->topdelta != ppp->topdelta ) goto reject_1;
1463 if( rpp->length != ppp->length ) goto reject_1;
1464 // skip leading pad, and trailing pad
1465 if( memcmp( ((byte*)rpp)+3, ((byte*)ppp)+3, len ) ) goto reject_1;
1466 // next post
1467 len += 4; // sizeof post_t + lead pad + trail pad
1468 rpp = (post_t *) (((byte *)rpp) + len);
1469 ppp = (post_t *) (((byte *)ppp) + len);
1470 }
1471 if ( ppp->topdelta == 0xff )
1472 {
1473 // columns match
1474 reuse_column = rtx;
1475 break;
1476 }
1477 reject_1:
1478 continue;
1479 #endif
1480 }
1481 }
1482 }
1483 livepatchcount++;
1484
1485 #ifdef DEEPSEA_TALL_PATCH
1486 // When the column topdelta is <= the current topdelta,
1487 // it is a DeePsea tall patch relative topdelta.
1488 int topdelta = cp->postptr->topdelta;
1489 if( topdelta <= cp->cur_topdelta )
1490 {
1491 // DeePsea relative topdelta
1492 topdelta += cp->cur_topdelta;
1493 }
1494 cp->cur_topdelta = topdelta;
1495 cp->nxt_y = cp->originy + topdelta;
1496 #else
1497 cp->nxt_y = cp->originy + cp->postptr->topdelta;
1498 #endif
1499 cp->bot_y = cp->nxt_y + cp->postptr->length;
1500 }else{
1501 patch_off: // empty post
1502 // clip left and right by turning this patch off
1503 cp->postptr = NULL;
1504 cp->nxt_y = INT_MAX;
1505 cp->bot_y = INT_MAX;
1506 }
1507 } // for all patches
1508
1509 // [WDJ] Reuse shared column data instead of creating multiple copies.
1510 if( livepatchcount == 1 )
1511 {
1512 if( reuse_column >= 0 )
1513 {
1514 // reuse the column
1515 colofs[x] = colofs[reuse_column];
1516 #ifdef DEBUG_REUSECOL
1517 // DEBUG: enable to see column reuse
1518 if( DEBUG_REUSECOL )
1519 debug_Printf("GenerateTexture: reuse %i\n", reuse_column);
1520 #endif
1521 continue; // next x
1522 }
1523 }
1524
1525 // Assemble the patch column data from multiple patches to the composite.
1526 for(;;) // all posts in column
1527 {
1528 // Find next post y in this column.
1529 // Only need the last patch, as that overwrites every other patch.
1530 nxtpat = -1; // patch with next post
1531 segnxt_y = INT_MAX-64; // may be negative, must be < INT_MAX
1532 compat_t * cp = &compat[0];
1533 for (p=0; p<patchcount; p++, cp++)
1534 {
1535 // Skip over any patches that have been passed.
1536 // Includes those copied, or covered by those copied.
1537 while( cp->bot_y <= bottom )
1538 {
1539 // this post has been passed, go to next post
1540 cp->postptr = (post_t*)( ((byte*)cp->postptr) + cp->postptr->length + 4);
1541 if( cp->postptr->topdelta == 0xFF ) // end of post column
1542 {
1543 // turn this patch off
1544 cp->postptr = NULL;
1545 cp->nxt_y = INT_MAX; // beyond texture size
1546 cp->bot_y = INT_MAX;
1547 break;
1548 }
1549
1550 #ifdef DEEPSEA_TALL_PATCH
1551 // When the column topdelta is <= the current topdelta,
1552 // it is a DeePsea tall patch relative topdelta.
1553 int topdelta = cp->postptr->topdelta;
1554 if( topdelta <= cp->cur_topdelta )
1555 {
1556 // DeePsea relative topdelta
1557 topdelta += cp->cur_topdelta;
1558 }
1559 cp->cur_topdelta = topdelta;
1560 cp->nxt_y = cp->originy + topdelta;
1561 #else
1562 cp->nxt_y = cp->originy + cp->postptr->topdelta;
1563 #endif
1564 cp->bot_y = cp->nxt_y + cp->postptr->length;
1565 }
1566
1567 if( cp->nxt_y <= segnxt_y )
1568 {
1569 // Found an active post
1570 nxtpat = p; // last draw into this segment
1571 // Check for continuing in the middle of a post.
1572 segnxt_y = (cp->nxt_y < bottom)?
1573 bottom // continue previous
1574 : cp->nxt_y; // start at top of post
1575 // Only a later drawn patch can overwrite this post.
1576 segbot_y = cp->bot_y;
1577 }
1578 else
1579 {
1580 // Limit bottom of this post segment by later drawn posts.
1581 if( cp->nxt_y < segbot_y ) segbot_y = cp->nxt_y;
1582 }
1583 }
1584 // Exit test, end of column, which may be empty
1585 if( segnxt_y >= texture->height ) break;
1586
1587 // copy whole/remainder of post, or cut it short
1588 // assert: segbot_y <= cp->bot_y+1 because it is set in loop
1589 if( segbot_y > texture->height ) segbot_y = texture->height;
1590
1591 seglen = segbot_y - segnxt_y;
1592
1593 if( postlength != 0 )
1594 {
1595 // Check if next patch does not append to bottom of current patch
1596 // Combined with Detect.
1597 if( segnxt_y > bottom )
1598 {
1599 detect_hole = TD_hole; // whole texture
1600 if( bottom > 0 ) postlength = 0; // start new post
1601 }
1602 if( postlength + seglen > 255 ) // if postlength would be too long
1603 {
1604 detect_post = TD_post; // whole texture
1605 postlength = 0; // start new post
1606 }
1607 if( postlength == 0 )
1608 {
1609 // does not append, start new post after existing post
1610 destpost = (post_t*)((byte*)destpost + destpost->length + 4);
1611 }
1612 }
1613
1614 // Only one patch is drawn last in this segment, copy that one
1615 cp = &compat[nxtpat];
1616 srcpost = cp->postptr;
1617 // offset>0 when copy starts part way into this source post
1618 // NOTE: cp->nxt_y = cp->originy + srcpost->topdelta;
1619 offset = ( segnxt_y > cp->nxt_y )? (segnxt_y - cp->nxt_y) : 0;
1620 // consider y clipping problem
1621 if( cp->nxt_y < 0 && !corrected_clipping )
1622 {
1623 // Original doom had bug in y clipping, such that it
1624 // would clip the width but not skip the source pixels.
1625 // Given that segnxt_y was already correctly clipped.
1626 offset += cp->nxt_y; // reproduce original doom clipping
1627 }
1628
1629 if( postlength == 0 )
1630 {
1631 // Start a new post
1632 if( destpixels + 3 >= texture_end ) goto exceed_alloc_error;
1633
1634 #ifdef DEEPSEA_TALL_PATCH
1635 if( segnxt_y > 254 )
1636 {
1637 // Can also create a DeePsea patch.
1638 // When the column topdelta is <= the current topdelta,
1639 // it is a DeePsea tall patch relative topdelta.
1640 int ds_topdelta = segnxt_y - seg_topdelta;
1641 if( ds_topdelta > seg_topdelta ) goto exceed_topdelta;
1642 // DeePsea relative topdelta successful.
1643 destpost->topdelta = ds_topdelta;
1644 detect_post = TD_post; // Due to DeePsea
1645 }
1646 else
1647 {
1648 // new post header and 0 pad byte
1649 destpost->topdelta = segnxt_y;
1650 }
1651 seg_topdelta = segnxt_y;
1652 #else
1653 if( segnxt_y > 254 ) goto exceed_topdelta;
1654 // new post header and 0 pad byte
1655 destpost->topdelta = segnxt_y;
1656 #endif
1657 // append at
1658 destpixels = (byte*)destpost + 3;
1659 destpixels[-1] = 0; // pad 0
1660 }
1661
1662 seglen = segbot_y - segnxt_y;
1663 if( destpixels + seglen + 3 >= texture_end ) goto exceed_alloc_error;
1664
1665 // append to existing post
1666 memcpy( destpixels, ((byte*)srcpost + offset + 3), seglen );
1667 destpixels += seglen;
1668 postlength += seglen;
1669 bottom = segbot_y;
1670 // finish post bookkeeping so can terminate loop easily
1671 *destpixels = 0; // pad 0
1672 if( postlength > 255 ) goto exceed_post_length;
1673 destpost->length = postlength;
1674 } // for all posts in column
1675 destpixels++; // skip pad 0
1676 *destpixels++ = 0xFF; // mark end of column
1677 // may be empty column so do not reference destpost
1678 continue; // next x
1679
1680 // [WDJ] Realloc texture memory, when estimate was too small.
1681 exceed_alloc_error:
1682 {
1683 // Re-alloc the texture
1684 byte* old_txcblock = txcblock;
1685 int old_txcblocksize = txcblocksize;
1686 // inc alloc by a proportional amount, plus one column
1687 txcblocksize += (texture->width - x + 1) * txcblocksize / texture->width;
1688 #if 1
1689 // enable to print re-alloc events
1690 if( verbose )
1691 GenPrintf(EMSG_ver, "R_GenerateTexture: %8s re-alloc from %i to %i\n",
1692 texture->name, old_txcblocksize, txcblocksize );
1693 #endif
1694 txcblock = Z_Malloc (txcblocksize, PU_IN_USE, (void**)&texren->cache);
1695 memcpy( txcblock, old_txcblock, old_txcblocksize );
1696 texture_end = txcblock + txcblocksize - 2; // do not exceed
1697 txcdata = (byte*)txcblock + colofs_size + 8; // posting area
1698 destpixels = (byte*)txcblock + colofs[x] - 3; // this column
1699 {
1700 patch_t * txcpatch = (patch_t*) txcblock; // header of txcblock
1701 colofs = (uint32_t*)&(txcpatch->columnofs); // has patch header
1702 }
1703 x--; // redo this column
1704 Z_Free(old_txcblock); // also nulls texturecache ptr
1705 texren->cache = txcblock; // replace ptr undone by Z_Free
1706 }
1707
1708 } // for x
1709
1710 if( destpixels >= texture_end )
1711 {
1712 I_SoftError("R_GenerateTexture: %8s final exceeds allocation %i, used %i bytes\n",
1713 texture->name, txcblocksize, destpixels - txcblock );
1714 }
1715
1716 // Interface for texture draw.
1717 // Texture data is after the offset table, no patch header.
1718 texren->columnofs = colofs;
1719 texren->pixel_data_offset = 3; // skip over post header and pad byte
1720 texren->texture_model = TM_combine_patch; // transparent combined
1721
1722 detect |= detect_hole | detect_post;
1723 #if 0
1724 // Enable to print memory usage
1725 I_SoftError("R_GenerateTexture: %8s allocated %i, used %i bytes\n",
1726 texture->name, txcblocksize, destpixels - txcblock );
1727 #endif
1728 goto done;
1729
1730 exceed_topdelta:
1731 I_SoftError("R_GenerateTexture: %8s topdelta= %i exceeds 254, make picture\n",
1732 texture->name, segnxt_y );
1733 goto error_redo_as_picture;
1734
1735 exceed_post_length:
1736 I_SoftError("R_GenerateTexture: %8s post length= %i exceeds 255, make picture\n",
1737 texture->name, postlength );
1738
1739 error_redo_as_picture:
1740 Z_Free( txcblock );
1741
1742 picture_format:
1743 //
1744 // multi-patch textures (or 'composite')
1745 // These are stored in a picture format and use a different drawing routine,
1746 // which is flagged by TM_picture.
1747 // Format:
1748 // array[ width ] of column offset
1749 // array[ width ] of column ( array[ height ] pixels )
1750
1751 txcblocksize = colofs_size + (texture->width * texture->height);
1752 //debug_Printf ("R_GenTex MULTI %.8s size: %d\n",texture->name,txcblocksize);
1753
1754 // will change PU_ at end of this function
1755 txcblock = Z_Malloc (txcblocksize, PU_IN_USE, (void**)&texren->cache);
1756 memset( txcblock + colofs_size, 0, txcblocksize - colofs_size ); // black background
1757
1758 // columns lookup table
1759 colofs = (uint32_t*)txcblock; // has no patch header
1760
1761 // [WDJ] column offset must cover entire texture, not just under patches
1762 // and it does not vary with the patches.
1763 x1 = colofs_size; // offset to first column, past colofs array
1764 for (x=0; x<texture->width; x++)
1765 {
1766 // generate column offset lookup
1767 // colofs[x] = (x * texture->height) + (texture->width*4);
1768 colofs[x] = x1;
1769 x1 += texture->height;
1770 }
1771
1772 // Composite the columns together.
1773 // The TM_picture format has data in full height columns.
1774 texpatch = texture->patches;
1775 for (i=0; i<texture->patchcount; i++, texpatch++)
1776 {
1777 // [WDJ] patch only used in this loop, without any other Z_Malloc
1778 // [WDJ] Must use common patch read to preserve endian consistency.
1779 // otherwise it will be in cache without endian changes.
1780 // To avoid hardware render cache.
1781 realpatch = W_CachePatchNum_Endian(texpatch->lumpnum, PU_CACHE); // patch temp
1782 x1 = texpatch->originx;
1783 if( x1 > texture->width )
1784 continue; // ignore PNG and other bad patches
1785
1786 x2 = x1 + realpatch->width;
1787 if( x2 < 0 )
1788 continue; // ignore PNG and other bad patches
1789
1790 if (x2 > texture->width)
1791 x2 = texture->width;
1792
1793 for( x = (x1<0)? 0 : x1; x<x2 ; x++ )
1794 {
1795 // source patch column from wad, to be copied
1796 column_t* patchcol =
1797 (column_t *)( (byte *)realpatch + realpatch->columnofs[x-x1] );
1798
1799 R_DrawColumnInCache (patchcol, // source
1800 txcblock + colofs[x], // dest
1801 texpatch->originy,
1802 texture->height); // limit
1803 }
1804 }
1805
1806 // Interface for texture draw.
1807 // Texture data is after the offset table, no patch header.
1808 texren->columnofs = colofs;
1809 texren->pixel_data_offset = 0;
1810 texren->texture_model = TM_picture; // non-transparent picture format
1811
1812 done:
1813 if( (detect & (TD_post | TD_hole)) == 0 )
1814 detect |= TD_solid_column; // can be drawn by wall column draw
1815 texren->detect = detect;
1816
1817 // unlock all the patches, no longer needed, but may be in another texture
1818 for( p=0; p<patchcount; p++ )
1819 {
1820 Z_ChangeTag (compat[p].patch, PU_CACHE);
1821 }
1822
1823 // Now that the texture has been built in column cache,
1824 // texture cache is purgable from zone memory.
1825 Z_ChangeTag (txcblock, PU_PRIV_CACHE); // priority because of expense
1826 texturememory += txcblocksize; // global
1827
1828 return txcblock;
1829 }
1830
1831
1832 // Public
1833 // texture_req : requirement, TM_none, TM_masked, TM_picture, or TM_picture_column
R_GenerateTexture(texture_render_t * texren,byte texture_req)1834 byte* R_GenerateTexture ( texture_render_t * texren, byte texture_req )
1835 {
1836 return R_GenerateTexture2( texren - texture_render, texren, texture_req );
1837 }
1838
1839
1840
1841
1842 // convert flat to hicolor as they are requested
1843 //
1844 //byte** flatcache;
1845
R_GetFlat(int flatlumpnum)1846 byte* R_GetFlat (int flatlumpnum)
1847 {
1848 // [WDJ] Checking all callers shows that they might tolerate PU_CACHE,
1849 // but this is safer, and has less reloading of the flats
1850 return W_CacheLumpNum (flatlumpnum, PU_LUMP); // flat image
1851 // return W_CacheLumpNum (flatlumpnum, PU_CACHE);
1852
1853 /* // this code work but is useless
1854 byte* data;
1855 short* wput;
1856 int i,j;
1857
1858 //FIXME: work with run time pwads, flats may be added
1859 // lumpnum to flatnum in flatcache
1860 if ((data = flatcache[flatlumpnum-firstflat])!=0)
1861 return data;
1862
1863 data = W_CacheLumpNum (flatlumpnum, PU_CACHE);
1864 i=W_LumpLength(flatlumpnum);
1865
1866 Z_Malloc (i,PU_STATIC,&flatcache[flatlumpnum-firstflat]);
1867 memcpy (flatcache[flatlumpnum-firstflat], data, i);
1868
1869 return flatcache[flatlumpnum-firstflat];
1870 */
1871
1872 /* // this code don't work because it don't put a proper user in the z_block
1873 if ((data = flatcache[flatlumpnum-firstflat])!=0)
1874 return data;
1875
1876 data = (byte *) W_CacheLumpNum(flatlumpnum,PU_LEVEL);
1877 flatcache[flatlumpnum-firstflat] = data;
1878 return data;
1879
1880 flatlumpnum -= firstflat;
1881
1882 if (vid.drawmode==DRAW8PAL)
1883 {
1884 flatcache[flatlumpnum] = data;
1885 return data;
1886 }
1887
1888 // allocate and convert to high color
1889
1890 wput = (short*) Z_Malloc (64*64*2,PU_STATIC,&flatcache[flatlumpnum]);
1891 //flatcache[flatlumpnum] =(byte*) wput;
1892
1893 for (i=0; i<64; i++)
1894 for (j=0; j<64; j++)
1895 wput[i*64+j] = ((color8to16[*data++]&0x7bde) + ((i<<9|j<<4)&0x7bde))>>1;
1896
1897 //Z_ChangeTag (data, PU_CACHE);
1898
1899 return (byte*) wput;
1900 */
1901 }
1902
1903 //
1904 // Empty the texture cache (used for load wad at runtime)
1905 //
R_Flush_Texture_Cache(void)1906 void R_Flush_Texture_Cache (void)
1907 {
1908 int i;
1909
1910 if (numtextures>0)
1911 {
1912 for (i=0; i<numtextures; i++)
1913 {
1914 // Z_Free also sets the cache ptr to NULL
1915 if( texture_render[i].cache )
1916 Z_Free( texture_render[i].cache );
1917 }
1918 }
1919
1920 R_Release_all_extra_texren();
1921 }
1922
1923 //
1924 // R_Load_Textures
1925 // Initializes the texture list with the textures from the world map.
1926 //
1927 // [WDJ] Original Doom bug: conflict between texture[0] and 0=no-texture.
1928 // Their solution was to not use the first texture.
1929 // In Doom1 == AASTINKY, FreeDoom == AASHITTY, Heretic = BADPATCH.
1930 // Because any wad compatible with other doom engines, like prboom,
1931 // will not be using texture[0], there is little incentive to fix this bug.
1932 // It is likely that texture[0] will be a duplicate of some other texture.
1933 #define BUGFIX_TEXTURE0
1934 //
1935 //
R_Load_Textures(void)1936 void R_Load_Textures (void)
1937 {
1938 maptexture_t* mtexture;
1939 texture_t* texture;
1940 mappatch_t* mpatch;
1941 texpatch_t* texpatch;
1942 char* pnames;
1943
1944 int i,j;
1945
1946 uint32_t * maptex, * maptex1, * maptex2; // 4 bytes, in wad
1947 uint32_t * directory; // in wad
1948
1949 char name[9];
1950 char* name_p;
1951
1952 lumpnum_t * patch_to_num; // patch name to num lookup
1953
1954 int nummappatches;
1955 int offset;
1956 int maxoff;
1957 int maxoff2;
1958 int numtextures1;
1959 int numtextures2;
1960
1961
1962
1963 // free previous memory before numtextures change
1964
1965 if (numtextures>0)
1966 {
1967 for (i=0; i<numtextures; i++)
1968 {
1969 // Z_Free also sets the cache ptr to NULL
1970 if (textures[i])
1971 Z_Free (textures[i]);
1972 if( texture_render[i].cache )
1973 Z_Free( texture_render[i].cache );
1974 }
1975 }
1976
1977 // Load the patch names from pnames.lmp.
1978 name[8] = 0;
1979 pnames = W_CacheLumpName ("PNAMES", PU_LUMP); // temp
1980 // [WDJ] Do endian as use pnames temp
1981 nummappatches = LE_SWAP32 ( *((uint32_t *)pnames) ); // pnames lump [0..3]
1982 name_p = pnames+4; // in lump, after number (uint32_t) is list of patch names
1983
1984 // create name index to patch index lookup table, will free before return
1985 patch_to_num = calloc (nummappatches, sizeof(*patch_to_num));
1986 for (i=0 ; i<nummappatches ; i++)
1987 {
1988 strncpy (name,name_p+i*8, 8);
1989 patch_to_num[i] = W_Check_Namespace( name, LNS_patch ); // NO_LUMP when invalid
1990 }
1991 Z_Free (pnames);
1992
1993 // Load the map texture definitions from textures.lmp.
1994 // The data is contained in one or two lumps,
1995 // TEXTURE1 for shareware, plus TEXTURE2 for commercial.
1996 maptex = maptex1 = W_CacheLumpName ("TEXTURE1", PU_LUMP); // will be freed
1997 numtextures1 = LE_SWAP32(*maptex); // number of textures, lump[0..3]
1998 maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
1999 directory = maptex+1; // after number of textures, at lump[4]
2000
2001 if( VALID_LUMP( W_CheckNumForName ("TEXTURE2") ) )
2002 {
2003 maptex2 = W_CacheLumpName ("TEXTURE2", PU_LUMP); // will be freed
2004 numtextures2 = LE_SWAP32(*maptex2); // number of textures, lump[0..3]
2005 maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
2006 }
2007 else
2008 {
2009 maptex2 = NULL;
2010 numtextures2 = 0;
2011 maxoff2 = 0;
2012 }
2013 #ifdef BUGFIX_TEXTURE0
2014 #define FIRST_TEXTURE 1
2015 // [WDJ] make room for using 0 as no-texture and keeping first texture
2016 numtextures = numtextures1 + numtextures2 + 1;
2017 #else
2018 numtextures = numtextures1 + numtextures2;
2019 #define FIRST_TEXTURE 0
2020 #endif
2021
2022
2023 // [smite] separate allocations, fewer horrible bugs
2024 if (textures)
2025 {
2026 Z_Free(textures);
2027 Z_Free(texture_render);
2028 Z_Free(textureheight);
2029 }
2030
2031 textures = Z_Malloc(numtextures * sizeof(*textures), PU_STATIC, 0);
2032 texture_render = Z_Malloc(numtextures * sizeof(texture_render_t), PU_STATIC, 0);
2033 // NULL the cache ptrs, format, and flags.
2034 memset( texture_render, 0, sizeof(texture_render_t) * numtextures );
2035 textureheight = Z_Malloc(numtextures * sizeof(*textureheight), PU_STATIC, 0);
2036
2037 #ifdef BUGFIX_TEXTURE0
2038 for (i=0 ; i<numtextures-1 ; i++, directory++)
2039 #else
2040 for (i=0 ; i<numtextures ; i++, directory++)
2041 #endif
2042 {
2043 //only during game startup
2044 //if (!(i&63))
2045 // CONS_Printf (".");
2046
2047 if (i == numtextures1)
2048 {
2049 // Start looking in second texture file.
2050 maptex = maptex2;
2051 maxoff = maxoff2;
2052 directory = maptex+1; // after number of textures, at lump[4]
2053 }
2054
2055 // offset to the current texture in TEXTURESn lump
2056 offset = LE_SWAP32(*directory); // next uint32_t
2057
2058 if (offset > maxoff)
2059 I_Error ("R_Load_Textures: bad texture directory\n");
2060
2061 // maptexture describes texture name, size, and
2062 // used patches in z order from bottom to top
2063 // Ptr to texture header in lump
2064 mtexture = (maptexture_t *) ( (byte *)maptex + offset);
2065
2066 // Texture struct allocation is dependent upon number of patches.
2067 texture = textures[i] =
2068 Z_Malloc (sizeof(texture_t)
2069 + sizeof(texpatch_t)*((uint16_t)(LE_SWAP16(mtexture->patchcount))-1),
2070 PU_STATIC, 0);
2071
2072 // get texture info from texture lump
2073 texture->width = (uint16_t)( LE_SWAP16(mtexture->width) );
2074 texture->height = (uint16_t)( LE_SWAP16(mtexture->height) );
2075 texture->patchcount = (uint16_t)( LE_SWAP16(mtexture->patchcount) );
2076 texture->detect = (mtexture->masked)? TD_masked : 0; // hint
2077
2078 // Sparc requires memmove, becuz gcc doesn't know mtexture is not aligned.
2079 // gcc will replace memcpy with two 4-byte read/writes, which will bus error.
2080 memmove(texture->name, mtexture->name, sizeof(texture->name));
2081 #if 0
2082 // [WDJ] DEBUG TRACE, watch where the textures go
2083 debug_Printf( "Texture[%i] = %8.8s\n", i, mtexture->name);
2084 #endif
2085 mpatch = &mtexture->patches[0]; // first patch ind in texture lump
2086 texpatch = &texture->patches[0];
2087
2088 for (j=0 ; j<texture->patchcount ; j++, mpatch++, texpatch++)
2089 {
2090 // get texture patch info from texture lump
2091 texpatch->originx = LE_SWAP16(mpatch->originx);
2092 texpatch->originy = LE_SWAP16(mpatch->originy);
2093 texpatch->lumpnum = patch_to_num[ (uint16_t)( LE_SWAP16(mpatch->patchnum) )];
2094 if( texpatch->lumpnum == NO_LUMP )
2095 {
2096 I_Error ("R_Load_Textures: Missing patch in texture %s\n",
2097 texture->name);
2098 }
2099 }
2100
2101 // determine width power of 2
2102 #if 1
2103 // [WDJ] only need to determine if exact power of 2.
2104 j = 1;
2105 while (j < texture->width)
2106 j<<=1;
2107 #else
2108 // Largest power of 2 that fits within width.
2109 j = 1;
2110 while (j*2 <= texture->width)
2111 j<<=1;
2112 #endif
2113 if( j != texture->width )
2114 {
2115 // Odd width
2116 texture->detect |= TD_odd_width;
2117 j = 1; // make width_tile_mask = 0
2118 }
2119 texture_render[i].width_tile_mask = j-1;
2120 texture_render[i].width = texture->width;
2121 textureheight[i] = texture->height<<FRACBITS;
2122 }
2123
2124 Z_Free (maptex1);
2125 if (maptex2)
2126 Z_Free (maptex2);
2127 free(patch_to_num);
2128
2129 #ifdef BUGFIX_TEXTURE0
2130 // Move texture[0] to texture[numtextures-1]
2131 textures[numtextures-1] = textures[0];
2132 texture_render[numtextures-1] = texture_render[0];
2133 textureheight[numtextures-1] = textureheight[0];
2134 // cannot have ptr to texture in two places, will deallocate twice
2135 textures[0] = NULL; // force segfault on any access to textures[0]
2136 #endif
2137
2138 //added:01-04-98: this takes 90% of texture loading time..
2139 // Precalculate whatever possible.
2140
2141 // Create translation table for global animation.
2142 if (texturetranslation)
2143 Z_Free (texturetranslation);
2144
2145 // texturetranslation is 1 larger than texture tables, for some unknown reason
2146 texturetranslation = Z_Malloc ((numtextures+1)*sizeof(*texturetranslation),
2147 PU_STATIC, 0);
2148
2149 for (i=0 ; i<numtextures ; i++)
2150 texturetranslation[i] = i;
2151 }
2152
2153
R_CheckNumForNameList(const char * name,lumplist_t * list,int listsize)2154 lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t* list, int listsize)
2155 {
2156 int i;
2157 lumpnum_t ln;
2158 // from last entry to first entry
2159 for(i = listsize - 1; i > -1; i--)
2160 {
2161 ln = W_CheckNumForNamePwad(name, list[i].wadfile, list[i].firstlump);
2162 if( ! VALID_LUMP(ln) )
2163 continue; // not found
2164 if(LUMPNUM(ln) > (list[i].firstlump + list[i].numlumps) )
2165 continue; // not within START END
2166
2167 return ln;
2168 }
2169 return NO_LUMP;
2170 }
2171
2172
2173 // Extra colormaps
2174 lumplist_t * colormaplumps = NULL; // malloc
2175 int numcolormaplumps = 0;
2176
2177 // called by R_Load_Colormaps
R_Load_ExtraColormaps()2178 static void R_Load_ExtraColormaps()
2179 {
2180 lumpnum_t start_ln, end_ln;
2181 int cfile;
2182 int ln1;
2183
2184 numcolormaplumps = 0;
2185 colormaplumps = NULL;
2186 cfile = 0;
2187
2188 for(;cfile < numwadfiles; cfile ++)
2189 {
2190 start_ln = W_CheckNumForNamePwad("C_START", cfile, 0);
2191 if( ! VALID_LUMP(start_ln) )
2192 continue;
2193
2194 ln1 = LUMPNUM( start_ln );
2195 end_ln = W_CheckNumForNamePwad("C_END", cfile, ln1);
2196
2197 if( ! VALID_LUMP(end_ln) )
2198 {
2199 I_SoftError("R_Load_Colormaps: C_START without C_END\n");
2200 continue;
2201 }
2202
2203 if(WADFILENUM(start_ln) != WADFILENUM(end_ln))
2204 {
2205 I_SoftError("R_Load_Colormaps: C_START and C_END in different wad files!\n");
2206 continue;
2207 }
2208
2209 colormaplumps = (lumplist_t *)realloc(colormaplumps, sizeof(lumplist_t) * (numcolormaplumps + 1));
2210 colormaplumps[numcolormaplumps].wadfile = WADFILENUM(start_ln);
2211 ln1++;
2212 colormaplumps[numcolormaplumps].firstlump = ln1;
2213 colormaplumps[numcolormaplumps].numlumps = LUMPNUM(end_ln) - ln1;
2214 numcolormaplumps++;
2215 }
2216 }
2217
2218
2219
2220 lumplist_t* flats;
2221 int numflatlists;
2222
2223
2224 static
R_Load_Flats()2225 void R_Load_Flats ()
2226 {
2227 lumpnum_t start_ln, end_ln;
2228 int cfile, ln1, ln2;
2229
2230 numflatlists = 0;
2231 flats = NULL;
2232 cfile = 0;
2233
2234 for(;cfile < numwadfiles; cfile ++)
2235 {
2236 #ifdef DEBUG_FLAT
2237 debug_Printf( "Flats in file %i\n", cfile );
2238 #endif
2239 start_ln = W_CheckNumForNamePwad("F_START", cfile, 0);
2240 if( ! VALID_LUMP(start_ln) )
2241 {
2242 #ifdef DEBUG_FLAT
2243 debug_Printf( "F_START not found, file %i\n", cfile );
2244 #endif
2245 start_ln = W_CheckNumForNamePwad("FF_START", cfile, 0);
2246
2247 if( ! VALID_LUMP(start_ln) ) //If STILL NO_LUMP, search the whole file!
2248 {
2249 #ifdef DEBUG_FLAT
2250 debug_Printf( "FF_START not found, file %i\n", cfile );
2251 #endif
2252 end_ln = NO_LUMP;
2253 goto save_flat_list;
2254 }
2255 }
2256
2257 // Search for END after START.
2258 ln1 = LUMPNUM( start_ln );
2259 end_ln = W_CheckNumForNamePwad("F_END", cfile, ln1);
2260 if( ! VALID_LUMP(end_ln) )
2261 {
2262 #ifdef DEBUG_FLAT
2263 debug_Printf( "F_END not found, file %i\n", cfile );
2264 #endif
2265 end_ln = W_CheckNumForNamePwad("FF_END", cfile, ln1);
2266 #ifdef DEBUG_FLAT
2267 if( ! VALID_LUMP(end_ln) ) {
2268 debug_Printf( "FF_END not found, file %i\n", cfile );
2269 }
2270 #endif
2271 }
2272
2273 save_flat_list:
2274 flats = (lumplist_t *)realloc(flats, sizeof(lumplist_t) * (numflatlists + 1));
2275 flats[numflatlists].wadfile = cfile;
2276 if(end_ln == NO_LUMP)
2277 {
2278 flats[numflatlists].firstlump = 0;
2279 flats[numflatlists].numlumps = 0xffff; //Search the entire file!
2280 }
2281 else
2282 {
2283 // delimiting markers were found
2284 ln2 = LUMPNUM( end_ln );
2285 if( ln2 <= ln1 ) // should not be able to happen
2286 ln2 = 0xffff; // search entire wad
2287 flats[numflatlists].firstlump = ln1 + 1;
2288 flats[numflatlists].numlumps = ln2 - (ln1 + 1);
2289 }
2290 numflatlists++;
2291 continue;
2292 }
2293
2294 if(!numflatlists)
2295 I_Error("R_Load_Flats: No flats found!\n");
2296 }
2297
2298
2299
2300 // [WDJ] was R_GetFlatNumForName, but it does not cache like GetFlat
R_FlatNumForName(const char * name)2301 lumpnum_t R_FlatNumForName(const char *name)
2302 {
2303 // [WDJ] No use in saving F_START if are not going to use them.
2304 // FreeDoom, where a flat and sprite both had same name,
2305 // would display sprite as a flat, badly.
2306 // Use F_START and F_END first, to find flats without getting a non-flat,
2307 // and only if not found then try whole file.
2308
2309 lumpnum_t f_lumpnum = R_CheckNumForNameList(name, flats, numflatlists);
2310
2311 if( ! VALID_LUMP(f_lumpnum) ) {
2312 // BP:([WDJ] R_CheckNumForNameList) don't work with gothic2.wad
2313 // [WDJ] Some wads are reported to use a flat as a patch, but that would
2314 // have to be handled in the patch display code.
2315 // If this search finds a sprite, sound, etc., it will display
2316 // multi-colored confetti.
2317 f_lumpnum = W_CheckNumForName(name);
2318 }
2319
2320 if( ! VALID_LUMP(f_lumpnum) ) {
2321 // [WDJ] When not found, dont quit, use first flat by default.
2322 I_SoftError("R_FlatNumForName: Could not find flat %.8s\n", name);
2323 f_lumpnum = WADLUMP( flats[0].wadfile, flats[0].firstlump ); // default to first flat
2324 }
2325
2326 return f_lumpnum;
2327 }
2328
2329 // [WDJ] Manage the spritelump_t allocations
2330 // Still use this array so that rot=0 sprite can share one entry for all 8 rotations.
2331
expand_spritelump_alloc(void)2332 void expand_spritelump_alloc( void )
2333 {
2334 // [WDJ] Expand array and copy
2335 num_free_spritelump = 256;
2336 int request = num_spritelump + num_free_spritelump;
2337 // new array of spritelumps
2338 spritelump_t * sl_new = Z_Malloc (request*sizeof(spritelump_t), PU_STATIC, 0);
2339 if( spritelumps ) // existing
2340 {
2341 // move existing data
2342 memcpy( sl_new, spritelumps, sizeof(spritelump_t)*num_spritelump);
2343 Z_Free( spritelumps ); // old
2344 }
2345 spritelumps = sl_new;
2346 }
2347
2348 // Next free spritelump
R_Get_spritelump(void)2349 int R_Get_spritelump( void )
2350 {
2351 if( num_free_spritelump == 0 )
2352 expand_spritelump_alloc();
2353 num_free_spritelump--;
2354 return num_spritelump ++;
2355 }
2356
2357 //
2358 // R_Init_SpriteLumps
2359 // Finds the width and hoffset of all sprites in the wad,
2360 // so the sprite does not need to be cached completely
2361 // just for having the header info ready during rendering.
2362 //
2363
2364 //
2365 // allocate sprite lookup tables
2366 //
R_Init_SpriteLumps(void)2367 void R_Init_SpriteLumps (void)
2368 {
2369 // the original Doom used to set numspritelumps from S_END-S_START+1
2370
2371 // [WDJ] Initial allocation, will be expanded as needed
2372 expand_spritelump_alloc();
2373 }
2374
2375
2376 // ----------------------------------------
2377 // COLORMAPS
2378 //
2379 // COLORMAP lump : array[34] of mapping tables [256].
2380 // [0] : brightest, light level = 248..255, maps direct to palette colors
2381 // [31] : darkest, light level = 0..7, maps to grey,black
2382 // [32] : invulnerability map, maps to whites and grays
2383 // [33] : black map, maps entirely to black
2384 //
2385 // Specific palette colors:
2386 // [0] = black 0,0,0
2387 // [4] = white 255,255,255
2388 // [176] = red 255,0,0
2389 // [112] = green 103,223,95
2390 // [200] = blue 0,0,255
2391
2392 // Boom: Extra colormaps can be included in the wad. They are the same
2393 // size and format as the Doom colormap.
2394 // WATERMAP is predefined by Boom, but may be overloaded.
2395
2396
2397 // called by R_Load_Data
2398 static
R_Load_Colormaps(void)2399 void R_Load_Colormaps (void)
2400 {
2401 lumpnum_t ln;
2402
2403 // Load in the standard colormap lightmap tables (defined by lump),
2404 // now 64k aligned for smokie...
2405 ln = W_GetNumForName("COLORMAP");
2406 reg_colormaps = Z_MallocAlign ( W_LumpLength(ln), PU_STATIC, NULL, 16);
2407 W_ReadLump( ln, reg_colormaps );
2408
2409 //SoM: 3/30/2000: Init Boom colormaps.
2410 {
2411 R_Clear_Colormaps();
2412 R_Load_ExtraColormaps();
2413 }
2414 }
2415
2416
2417 static lumpnum_t extra_colormap_lumpnum[MAXCOLORMAPS]; // lump number
2418
2419 //SoM: Clears out extra colormaps between levels.
2420 // called by P_SetupLevel after ZFree(PU_LEVEL,..)
2421 // called by R_Load_Colormaps
R_Clear_Colormaps()2422 void R_Clear_Colormaps()
2423 {
2424 int i;
2425 #if 0
2426 if( num_extra_colormaps > 30 )
2427 GenPrintf(EMSG_warn, "Number of colormaps: %i\n", num_extra_colormaps );
2428 #endif
2429
2430 // extra_colormaps are always present [MAXCOLORMAPS]
2431 num_extra_colormaps = 0;
2432 for(i = 0; i < MAXCOLORMAPS; i++)
2433 {
2434 extra_colormap_lumpnum[i] = NO_LUMP;
2435 // [WDJ] The ZMalloc colormap used to be PU_LEVEL, releasing memory without setting the ptrs NULL.
2436 // It is now PU_COLORMAP, and it is released only by this function.
2437 if( extra_colormaps[i].colormap )
2438 {
2439 Z_Free( extra_colormaps[i].colormap );
2440 extra_colormaps[i].colormap = NULL;
2441 }
2442 }
2443 // memset(extra_colormaps, 0, sizeof(extra_colormaps));
2444 }
2445
2446
2447 // [WDJ] Enable to print out results of colormap generate.
2448 //#define VIEW_COLORMAP_GEN
2449
2450 // In order: whiteindex, lightgreyindex, medgreyindex, darkgreyindex, grayblackindex
2451 // redindex, greenindex, blueindex
2452 #define NUM_ANALYZE_COLORS 8
2453 static byte doom_analyze_index[NUM_ANALYZE_COLORS] = {
2454 4, 87, 96, 106, 7, 188, 123, 206
2455 };
2456 static byte heretic_analyze_index[NUM_ANALYZE_COLORS] = {
2457 35, 26, 18, 10, 253, 148, 213, 192
2458 };
2459
2460 // [WDJ] Analyze an extra colormap to derive some GL parameters
R_Colormap_Analyze(int mapnum)2461 void R_Colormap_Analyze( int mapnum )
2462 {
2463 extracolormap_t * colormapp = & extra_colormaps[ mapnum ];
2464 colormapp->fadestart = 0;
2465 colormapp->fadeend = 33;
2466 // colormapp->maskalpha = 0x0; // now in maskcolor
2467 colormapp->fog = 0;
2468
2469 #ifdef HWRENDER
2470 // Hardware renderer does not use, nor allocate, the colormap.
2471 // It uses the rgba field instead.
2472 if( rendermode == render_soft )
2473 #endif
2474 {
2475 // Software renderer defaults.
2476 // SoM: Added, we set all params of the colormap to normal because there
2477 // is no real way to tell how GL should handle a colormap lump anyway..
2478 colormapp->maskcolor.rgba = 0xffffffff; // white
2479 colormapp->maskcolor.s.alpha = 0;
2480 colormapp->fadecolor.rgba = 0x0; // black
2481 colormapp->rgba[0].rgba = 0xffffffff;
2482 colormapp->rgba[0].s.alpha = 0xe1;
2483 }
2484 #ifdef HWRENDER
2485 else
2486 {
2487 // Analyze the Boom colormap for the hardware renderer.
2488 // The Boom colormap has been loaded already.
2489 // lighttable_t = byte array
2490 byte * cm = colormapp->colormap; // Boom colormap
2491 byte * tstcolor = & doom_analyze_index[0]; // colors to test
2492 RGBA_t work_rgba;
2493 int i;
2494
2495 if( cm == NULL ) // no colormap to analyze
2496 {
2497 GenPrintf(EMSG_warn, "R_Colormap_Analyze: map %i, has no colormap\n", mapnum );
2498 return;
2499 }
2500
2501 if( EN_heretic )
2502 tstcolor = & heretic_analyze_index[0]; // heretic colors to test
2503
2504 // [WDJ] Analyze the colormap to get some imitative parameters.
2505 for(i=0; i<NUM_RGBA_LEVELS; i++)
2506 {
2507 // rgba[0]=darkest, rgba[NUM_RGBA_LEVELS-1] is the brightest
2508 // Within a range, analyze a map nearer the middle of the range.
2509 int mapindex = (((NUM_RGBA_LEVELS-1-i) * 32) + 8) / NUM_RGBA_LEVELS;
2510 // Estimate an alpha, could set it to max,
2511 // smaller alpha indicates washed out color.
2512 // This is completely ad-hoc, and rough. It purposely favors high alpha.
2513
2514 // Analyze 4
2515 // the brightest red, green, blue should have the same brightness
2516 float h4r = 0.0; // alpha = 1
2517 int cnt =0;
2518 int try_cnt = 0;
2519 int dd4, dn4, k1, k2;
2520 // for all combinations of tstcolor
2521 for( k1=0; k1<NUM_ANALYZE_COLORS-1; k1++ )
2522 {
2523 byte i1 = tstcolor[k1];
2524 byte cm1 = cm[ LIGHTTABLE(mapindex) + i1 ];
2525 for( k2=k1+1; k2<NUM_ANALYZE_COLORS; k2++ )
2526 {
2527 byte i2 = tstcolor[k2];
2528 byte cm2 = cm[ LIGHTTABLE(mapindex) + i2 ];
2529 // for each color
2530 int krgb;
2531 for( krgb=0; krgb<3; krgb++ ) // red, green, blue
2532 {
2533 // (1-h) = (cm[b].r - cm[r].r) / (p[b].r - p[r].r)
2534 switch( krgb )
2535 {
2536 case 0: // red
2537 dd4 = pLocalPalette[i1].s.red - pLocalPalette[i2].s.red;
2538 dn4 = pLocalPalette[cm1].s.red - pLocalPalette[cm2].s.red;
2539 break;
2540 case 1: // green
2541 dd4 = pLocalPalette[i1].s.green - pLocalPalette[i2].s.green;
2542 dn4 = pLocalPalette[cm1].s.green - pLocalPalette[cm2].s.green;
2543 break;
2544 default: // blue
2545 dd4 = pLocalPalette[i1].s.blue - pLocalPalette[i2].s.blue;
2546 dn4 = pLocalPalette[cm1].s.blue - pLocalPalette[cm2].s.blue;
2547 break;
2548 }
2549 if( dn4 && (dd4 > 0.01f || dd4 < -0.01f))
2550 {
2551 float h3 = (float)dn4 / (float)dd4;
2552 if( h3 > 1.0f ) h3 = 1.0;
2553 if( h3 < 0.01f ) h3 = 0.01f;
2554 h4r += h3; // total for avg
2555 cnt ++;
2556 }
2557 try_cnt ++; // for fog
2558 }
2559 }
2560 }
2561 h4r /= cnt;
2562 int m4_fog = 0;
2563 // h = 0.0 is a useless table
2564 if( h4r > 0.99 ) {
2565 h4r = 0.99f;
2566 m4_fog = 1;
2567 }
2568 if( h4r < 0.00 ) {
2569 h4r = 0.00;
2570 m4_fog = 1;
2571 }
2572 if( cnt * 2 < try_cnt )
2573 m4_fog = 1;
2574 h4r = h4r * (0.66f / 1.732f); // correction for testing at 1/3 max brightness
2575 float h4 = 1.0 - h4r;
2576 int m4_red, m4_blue, m4_green;
2577 #if 0
2578 // Generate color tint from changes grey.
2579 byte greyindex = tstcolor[2];
2580 byte cm_grey = cm[ LIGHTTABLE(mapindex) + greyindex ]; // grey
2581 // cr = (cm[w].r - (1-h) * p[w].r) / h ;
2582 m4_red = ( pLocalPalette[cm_grey].s.red - (h4r* pLocalPalette[greyindex].s.red)) / h4;
2583 if( m4_red > 255 ) m4_red = 255;
2584 if( m4_red < 0 ) m4_red = 0;
2585 // cg = (cm[w].g - (1-h) * p[w].g) / h ;
2586 m4_green = ( pLocalPalette[cm_grey].s.green - (h4r* pLocalPalette[greyindex].s.green)) / h4;
2587 if( m4_green > 255 ) m4_green = 255;
2588 if( m4_green < 0 ) m4_green = 0;
2589 // cb = (cm[w].b - (1-h) * p[w].b) / h ;
2590 m4_blue = ( pLocalPalette[cm_grey].s.blue - (h4r* pLocalPalette[greyindex].s.blue)) / h4;
2591 if( m4_blue > 255 ) m4_blue = 255;
2592 if( m4_blue < 0 ) m4_blue = 0;
2593 #else
2594 // Generate color tint from changes white.
2595 byte whiteindex = tstcolor[0];
2596 byte cm_white = cm[ LIGHTTABLE(mapindex) + whiteindex ]; // white
2597 // cr = (cm[w].r - (1-h) * p[w].r) / h ;
2598 m4_red = ( pLocalPalette[cm_white].s.red - (h4r* pLocalPalette[whiteindex].s.red)) / h4;
2599 if( m4_red > 255 ) m4_red = 255;
2600 if( m4_red < 0 ) m4_red = 0;
2601 // cg = (cm[w].g - (1-h) * p[w].g) / h ;
2602 m4_green = ( pLocalPalette[cm_white].s.green - (h4r* pLocalPalette[whiteindex].s.green)) / h4;
2603 if( m4_green > 255 ) m4_green = 255;
2604 if( m4_green < 0 ) m4_green = 0;
2605 // cb = (cm[w].b - (1-h) * p[w].b) / h ;
2606 m4_blue = ( pLocalPalette[cm_white].s.blue - (h4r* pLocalPalette[whiteindex].s.blue)) / h4;
2607 if( m4_blue > 255 ) m4_blue = 255;
2608 if( m4_blue < 0 ) m4_blue = 0;
2609 #endif
2610 #ifdef VIEW_COLORMAP_GEN
2611 // Enable to see results of analysis.
2612 GenPrintf(EMSG_info,
2613 "Analyze4: alpha=%i red=%i green=%i blue=%i fog=%i\n",
2614 (int)(255.0f*h4), m4_red, m4_green, m4_blue, m4_fog );
2615 #endif
2616 // Not great, get some tints wrong, and sometimes too light.
2617 // Give m4_fog some treatment, to stop compiler messages.
2618 work_rgba.s.alpha = (int)(h4 * 255.0f) - (m4_fog * 2.0f);
2619 work_rgba.s.red = m4_red;
2620 work_rgba.s.green = m4_green;
2621 work_rgba.s.blue = m4_blue;
2622
2623 colormapp->rgba[i].rgba = work_rgba.rgba; // to extra_colormap
2624
2625 #ifdef VIEW_COLORMAP_GEN
2626 // Enable to view settings of RGBA for hardware renderer.
2627 GenPrintf(EMSG_info,"RGBA[%i]: %8x (alpha=%i, R=%i, G=%i, B=%i)\n",
2628 i, colormapp->rgba[i].rgba,
2629 (int)work_rgba.s.alpha,
2630 (int)work_rgba.s.red, (int)work_rgba.s.green, (int)work_rgba.s.blue );
2631 #endif
2632 }
2633 // They had plans, but these are still unused in hardware renderer.
2634 colormapp->maskcolor.rgba = colormapp->rgba[NUM_RGBA_LEVELS-1].rgba;
2635 colormapp->fadecolor.rgba = colormapp->rgba[0].rgba;
2636
2637 }
2638 #endif
2639 }
2640
2641
2642
2643
2644 // [WDJ] The name parameter has trailing garbage, but the name lookup
2645 // only uses the first 8 chars.
2646 // Return the new colormap id number
R_ColormapNumForName(const char * name)2647 int R_ColormapNumForName(const char *name)
2648 {
2649 lumpnum_t lumpnum;
2650 int i;
2651
2652 // Check for existing colormap of same name
2653 lumpnum = R_CheckNumForNameList(name, colormaplumps, numcolormaplumps);
2654 if( ! VALID_LUMP(lumpnum) )
2655 {
2656 I_SoftError("R_ColormapNumForName: Cannot find colormap lump %8s\n", name);
2657 return 0;
2658 }
2659
2660 for(i = 0; i < num_extra_colormaps; i++)
2661 {
2662 if(lumpnum == extra_colormap_lumpnum[i])
2663 return i;
2664 }
2665
2666 // Add another colormap
2667 if(num_extra_colormaps == MAXCOLORMAPS)
2668 {
2669 I_SoftError("R_ColormapNumForName: Too many colormaps!\n");
2670 return 0;
2671 }
2672
2673 extra_colormap_lumpnum[num_extra_colormaps] = lumpnum;
2674 extracolormap_t * ecmp = & extra_colormaps[num_extra_colormaps];
2675
2676 // The extra_colormap structure is static and allocated ptrs in it must be set NULL upon release.
2677 // Align on 16 bits, like other colormap allocations.
2678 // ecmp->colormap =
2679 Z_MallocAlign (W_LumpLength(lumpnum), PU_COLORMAP, (void**)&(ecmp->colormap), 16);
2680 // read colormap tables [][] of byte, mapping to alternative palette colors
2681 W_ReadLump( lumpnum, ecmp->colormap );
2682
2683 #ifdef VIEW_COLORMAP_GEN
2684 GenPrintf(EMSG_info, "\nBoom Colormap: num=%i name= %8.8s\n", num_extra_colormaps, name );
2685 #endif
2686 R_Colormap_Analyze( num_extra_colormaps );
2687
2688 num_extra_colormaps++;
2689 return num_extra_colormaps - 1;
2690 }
2691
2692
2693
2694 // SoM:
2695 //
2696 // R_Create_Colormap
2697 // This is a more GL friendly way of doing colormaps: Specify colormap
2698 // data in a special linedef's texture areas and use that to generate
2699 // custom colormaps at runtime. NOTE: For GL mode, we only need to color
2700 // data and not the colormap data.
2701
2702 byte NearestColor(byte r, byte g, byte b);
2703 int RoundUp(double number);
2704 void R_Create_Colormap_ex( extracolormap_t * extra_colormap_p );
2705
2706 #define HEX_TO_INT(x) (x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
2707 #define ALPHA_TO_INT(x) (x >= 'a' && x <= 'z' ? x - 'a' : x >= 'A' && x <= 'Z' ? x - 'A' : 0)
2708 #define CHAR_TO_INT(c) (c >= '0' && c <= '9' ? c - '0' : 0)
2709 #define ABS2(x) ((x) < 0 ? -(x) : (x))
2710
2711 // [WDJ]
2712 // The colorstr is the toptexture name: '#' R(2) G(2) B(2) A(1)
2713 // The ctrlstr is the midtexture name. '#' FOG(1) FADE_BEGIN(2) FADE_END(2)
2714 // The fadestr is the bottomtexture name: '#' R(2) G(2) B(2).
2715 // Translations:
2716 // R(2), G(2), B(2): 2-digit HEX => 256 color (8bit)
2717 // A(1): char a-z or A-Z => 0 to 25 alpha
2718 // FOG: '0'= not-fog, '1'= fog-effect
2719 // FADE_BEGIN: 2-digit decimal (0..32) colormap where fade begins
2720 // FADE_END: 2-digit decimal (1..33) colormap where fade-to color is reached.
2721 // Return the new colormap id number
R_Create_Colormap_str(char * colorstr,char * ctrlstr,char * fadestr)2722 int R_Create_Colormap_str(char *colorstr, char *ctrlstr, char *fadestr)
2723 {
2724 extracolormap_t * extra_colormap_p;
2725 RGBA_t maskcolor, fadecolor;
2726 unsigned int fadestart = 0, fadeend = 33;
2727 int c_alpha = 0;
2728 int i;
2729 int fog = 0;
2730 int mapnum = num_extra_colormaps; // the new colormap id number
2731
2732 if(colorstr[0] == '#') // colormap generate string is recognized
2733 {
2734 // color value from top texture string
2735 maskcolor.s.red = ((HEX_TO_INT(colorstr[1])<<4) + HEX_TO_INT(colorstr[2]));
2736 maskcolor.s.green = ((HEX_TO_INT(colorstr[3])<<4) + HEX_TO_INT(colorstr[4]));
2737 maskcolor.s.blue = ((HEX_TO_INT(colorstr[5])<<4) + HEX_TO_INT(colorstr[6]));
2738 if(colorstr[7] >= 'a' && colorstr[7] <= 'z')
2739 c_alpha = (colorstr[7] - 'a');
2740 else if(colorstr[7] >= 'A' && colorstr[7] <= 'Z')
2741 c_alpha = (colorstr[7] - 'A');
2742 else
2743 c_alpha = 25;
2744 maskcolor.s.alpha = (c_alpha * 255) / 25; // convert from 0..25 to 0..255
2745 }
2746 else
2747 {
2748 // [WDJ] default for missing upper is not in docs, and was inconsistent
2749 // Cannot be 0xff after multiply by maskalpha=0.
2750 maskcolor.s.red = 0xff;
2751 maskcolor.s.green = 0xff;
2752 maskcolor.s.blue = 0xff;
2753 maskcolor.s.alpha = 0;
2754 }
2755
2756 if(ctrlstr[0] == '#')
2757 {
2758 // SoM: Get parameters like, fadestart, fadeend, and the fogflag...
2759 fadestart = CHAR_TO_INT(ctrlstr[3]) + (CHAR_TO_INT(ctrlstr[2]) * 10);
2760 fadeend = CHAR_TO_INT(ctrlstr[5]) + (CHAR_TO_INT(ctrlstr[4]) * 10);
2761 if(fadestart > 32 || fadestart < 0)
2762 fadestart = 0;
2763 if(fadeend > 33 || fadeend < 1)
2764 fadeend = 33;
2765 fog = CHAR_TO_INT(ctrlstr[1]) ? 1 : 0;
2766 }
2767
2768 fadecolor.rgba = 0;
2769 if(fadestr[0] == '#')
2770 {
2771 fadecolor.s.red = ((HEX_TO_INT(fadestr[1]) * 16) + HEX_TO_INT(fadestr[2]));
2772 fadecolor.s.green = ((HEX_TO_INT(fadestr[3]) * 16) + HEX_TO_INT(fadestr[4]));
2773 fadecolor.s.blue = ((HEX_TO_INT(fadestr[5]) * 16) + HEX_TO_INT(fadestr[6]));
2774 }
2775
2776 // find any identical existing colormap
2777 for(i = 0; i < num_extra_colormaps; i++)
2778 {
2779 // created colormaps only
2780 if( VALID_LUMP(extra_colormap_lumpnum[i]) )
2781 continue;
2782 if( maskcolor.rgba == extra_colormaps[i].maskcolor.rgba
2783 && fadecolor.rgba == extra_colormaps[i].fadecolor.rgba
2784 // [WDJ] maskalpha is now in maskcolor.alpha
2785 // && maskalpha == extra_colormaps[i].maskalpha
2786 && fadestart == extra_colormaps[i].fadestart
2787 && fadeend == extra_colormaps[i].fadeend
2788 && fog == extra_colormaps[i].fog )
2789 return i;
2790 }
2791
2792 #ifdef VIEW_COLORMAP_GEN
2793 GenPrintf(EMSG_info, "\nGenerate Colormap: num=%i\n", num_extra_colormaps );
2794 GenPrintf(EMSG_info, " alpha=%2x, color=(%2x,%2x,%2x), fade=(%2x,%2x,%2x), fog=%i\n",
2795 maskcolor.s.alpha, maskcolor.s.red, maskcolor.s.green, maskcolor.s.blue,
2796 fadecolor.s.red, fadecolor.s.green, fadecolor.s.blue,
2797 fog );
2798 #endif
2799
2800 if(num_extra_colormaps == MAXCOLORMAPS)
2801 {
2802 I_SoftError("R_Create_Colormap: Too many colormaps!\n");
2803 return 0;
2804 }
2805
2806 num_extra_colormaps++;
2807
2808 // Created colormaps do not have lumpnum
2809 extra_colormap_lumpnum[mapnum] = NO_LUMP;
2810 extra_colormap_p = &extra_colormaps[mapnum];
2811
2812 extra_colormap_p->colormap = NULL;
2813 extra_colormap_p->maskcolor.rgba = maskcolor.rgba;
2814 extra_colormap_p->fadecolor.rgba = fadecolor.rgba;
2815 // extra_colormap_p->maskalpha = maskalpha; // 0.0 .. 1.0 // now in maskcolor
2816 extra_colormap_p->fadestart = fadestart;
2817 extra_colormap_p->fadeend = fadeend;
2818 extra_colormap_p->fog = fog;
2819
2820 R_Create_Colormap_ex( extra_colormap_p );
2821
2822 #if 0
2823 #ifdef VIEW_COLORMAP_GEN
2824 if(rendermode != render_soft)
2825 {
2826 // [WDJ] DEBUG, TEST AGAINST OLD HDW CODE
2827 uint32_t rgba_oldhw =
2828 (HEX_TO_INT(colorstr[1]) << 4) + (HEX_TO_INT(colorstr[2]) << 0) +
2829 (HEX_TO_INT(colorstr[3]) << 12) + (HEX_TO_INT(colorstr[4]) << 8) +
2830 (HEX_TO_INT(colorstr[5]) << 20) + (HEX_TO_INT(colorstr[6]) << 16) +
2831 (ALPHA_TO_INT(colorstr[7]) << 24);
2832 if( rgba_oldhw != extra_colormap_p->rgba[0].rgba )
2833 GenPrintf(EMSG_info,"RGBA: old=%X, new=%x\n", rgba_oldhw, extra_colormap_p->rgba[i-1].rgba);
2834 }
2835 #endif
2836 #endif
2837
2838 return mapnum;
2839 }
2840
2841
2842 // Analyze param and create the colormap data for the rendermode.
2843 // Called when rendermode change.
R_Create_Colormap_ex(extracolormap_t * extra_colormap_p)2844 void R_Create_Colormap_ex( extracolormap_t * extra_colormap_p )
2845 {
2846 RGBA_t maskcolor, fadecolor;
2847 double color_r, color_g, color_b; // color RGB from top-texture
2848 double cfade_r, cfade_g, cfade_b; // fade-to color from bottom-texture
2849 double maskalpha;
2850 unsigned int fadestart, fadeend, c_alpha;
2851 int i;
2852 unsigned int p;
2853
2854 maskcolor.rgba = extra_colormap_p->maskcolor.rgba;
2855 fadecolor.rgba = extra_colormap_p->fadecolor.rgba;
2856 fadestart = extra_colormap_p->fadestart;
2857 fadeend = extra_colormap_p->fadeend;
2858
2859 c_alpha = maskcolor.s.alpha;
2860 maskalpha = (double)maskcolor.s.alpha / (double)255; // 0.0 .. 1.0
2861 color_r = (double)maskcolor.s.red;
2862 color_g = (double)maskcolor.s.green;
2863 color_b = (double)maskcolor.s.blue;
2864
2865 cfade_r = (double)fadecolor.s.red;
2866 cfade_g = (double)fadecolor.s.green;
2867 cfade_b = (double)fadecolor.s.blue;
2868
2869
2870 #ifdef HWRENDER
2871 // Hardware renderer does not use, nor allocate, the colormap.
2872 // It uses the rgba field instead.
2873 if(rendermode == render_soft)
2874 #endif
2875 {
2876 byte * colormap_p;
2877 double othermask = 1.0 - maskalpha;
2878 double by_alpha = maskalpha / 255.0;
2879 double fadedist = fadeend - fadestart;
2880 double deltas[256][3], map[256][3];
2881
2882 // The extra_colormap structure is static and allocated ptrs in it must be set NULL upon release.
2883 // Aligning on 16 bits, NOT 8, keeps it from crashing! SSNTails 12-13-2002
2884 if( extra_colormap_p->colormap == NULL )
2885 {
2886 // extra_colormap_p->colormap =
2887 Z_MallocAlign((256 * 34) + 10, PU_COLORMAP, (void**)&(extra_colormap_p->colormap), 16);
2888 }
2889 colormap_p = extra_colormap_p->colormap;
2890
2891 // premultiply, this messes up rgba calc so it must be done here
2892 color_r *= by_alpha; // to 0.0 .. 1.0 range
2893 color_g *= by_alpha;
2894 color_b *= by_alpha;
2895 for(i = 0; i < 256; i++)
2896 {
2897 double r = pLocalPalette[i].s.red;
2898 double g = pLocalPalette[i].s.green;
2899 double b = pLocalPalette[i].s.blue;
2900 double cbrightness = sqrt((r*r) + (g*g) + (b*b));
2901
2902 map[i][0] = (cbrightness * color_r) + (r * othermask);
2903 if(map[i][0] > 255.0)
2904 map[i][0] = 255.0;
2905 deltas[i][0] = (map[i][0] - cfade_r) / fadedist;
2906
2907 map[i][1] = (cbrightness * color_g) + (g * othermask);
2908 if(map[i][1] > 255.0)
2909 map[i][1] = 255.0;
2910 deltas[i][1] = (map[i][1] - cfade_g) / fadedist;
2911
2912 map[i][2] = (cbrightness * color_b) + (b * othermask);
2913 if(map[i][2] > 255.0)
2914 map[i][2] = 255.0;
2915 deltas[i][2] = (map[i][2] - cfade_b) / fadedist;
2916 }
2917
2918 for(p = 0; p < 34; p++)
2919 {
2920 for(i = 0; i < 256; i++)
2921 {
2922 *colormap_p = NearestColor(RoundUp(map[i][0]), RoundUp(map[i][1]), RoundUp(map[i][2]));
2923 colormap_p++;
2924
2925 if( p < fadestart )
2926 continue;
2927
2928 if(ABS2(map[i][0] - cfade_r) > ABS2(deltas[i][0]))
2929 map[i][0] -= deltas[i][0];
2930 else
2931 map[i][0] = cfade_r;
2932
2933 if(ABS2(map[i][1] - cfade_g) > ABS2(deltas[i][1]))
2934 map[i][1] -= deltas[i][1];
2935 else
2936 map[i][1] = cfade_g;
2937
2938 if(ABS2(map[i][2] - cfade_b) > ABS2(deltas[i][1]))
2939 map[i][2] -= deltas[i][2];
2940 else
2941 map[i][2] = cfade_b;
2942 }
2943 }
2944 }
2945 #ifdef HWRENDER
2946 else
2947 {
2948 if( extra_colormap_p->colormap )
2949 {
2950 // Does not use colormap
2951 Z_Free( extra_colormap_p->colormap );
2952 extra_colormap_p->colormap = NULL;
2953 }
2954
2955 // hardware needs color_r, color_g, color_b, before they get *maskalpha.
2956 for( i=0; i<NUM_RGBA_LEVELS; i++ )
2957 {
2958 // rgba[0]=darkest, rgba[NUM_RGBA_LEVELS-1] is the brightest
2959 int mapindex = ((NUM_RGBA_LEVELS-1-i) * 34) / NUM_RGBA_LEVELS;
2960 double colorper, fadeper;
2961 if( mapindex <= fadestart )
2962 {
2963 colorper = 1.0; // rgba = color
2964 fadeper = 0.0;
2965 }
2966 else if( mapindex < fadeend )
2967 {
2968 // mapindex != fadeend, fadeend != fadestart
2969 // proportional ramp from color to fade color
2970 colorper = ((double)(fadeend-mapindex))/(fadeend-fadestart);
2971 fadeper = 1.0 - colorper;
2972 }
2973 else
2974 {
2975 // fadeend and after
2976 colorper = 0.0;
2977 fadeper = 1.0; // rgba = fade
2978 }
2979
2980 RGBA_t * cp = & extra_colormap_p->rgba[i];
2981 cp->s.red = (int)( colorper*color_r + fadeper*cfade_r );
2982 cp->s.green = (int)( colorper*color_g + fadeper*cfade_g );
2983 cp->s.blue = (int)( colorper*color_b + fadeper*cfade_b );
2984 cp->s.alpha = c_alpha;
2985 #ifdef VIEW_COLORMAP_GEN
2986 GenPrintf(EMSG_info,"RGBA[%i]: %x\n", i, extra_colormap_p->rgba[i].rgba);
2987 #endif
2988 }
2989 }
2990 #endif
2991 }
2992 #undef ALPHA_TO_INT
2993 #undef HEX_TO_INT
2994 #undef ABS2
2995
2996
2997 //Thanks to quake2 source!
2998 //utils3/qdata/images.c
NearestColor(byte r,byte g,byte b)2999 byte NearestColor(byte r, byte g, byte b)
3000 {
3001 int dr, dg, db;
3002 int distortion;
3003 int bestdistortion = 256 * 256 * 4;
3004 int bestcolor = 0;
3005 int i;
3006
3007 for(i = 0; i < 256; i++) {
3008 dr = r - pLocalPalette[i].s.red;
3009 dg = g - pLocalPalette[i].s.green;
3010 db = b - pLocalPalette[i].s.blue;
3011 distortion = dr*dr + dg*dg + db*db;
3012 if(distortion < bestdistortion) {
3013
3014 if(!distortion)
3015 return i;
3016
3017 bestdistortion = distortion;
3018 bestcolor = i;
3019 }
3020 }
3021
3022 return bestcolor;
3023 }
3024
3025
3026 // Rounds off floating numbers and checks for 0 - 255 bounds
RoundUp(double number)3027 int RoundUp(double number)
3028 {
3029 if(number > 255.0)
3030 return 255;
3031 if(number < 0)
3032 return 0;
3033
3034 if((int)number <= (int)(number -0.5))
3035 return (int)number + 1;
3036
3037 return (int)number;
3038 }
3039
3040
3041
3042
R_ColormapNameForNum(int num)3043 char * R_ColormapNameForNum(int num)
3044 {
3045 if(num == -1)
3046 return "NONE";
3047
3048 if(num < 0 || num > MAXCOLORMAPS)
3049 {
3050 I_SoftError("R_ColormapNameForNum: num is invalid!\n");
3051 return "NONE";
3052 }
3053
3054 if( ! VALID_LUMP(extra_colormap_lumpnum[num]) )
3055 return "INLEVEL"; // created colormap
3056
3057 return wadfiles[WADFILENUM(extra_colormap_lumpnum[num])]->lumpinfo[LUMPNUM(extra_colormap_lumpnum[num])].name;
3058 }
3059
3060
3061 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 ) || defined( ENABLE_DRAW24 ) || defined( ENABLE_DRAW32 )
3062 //
3063 // build a table for quick conversion from 8bpp to 15bpp, 16bpp, 24bpp, 32bpp
3064 //
3065 // covert 8 bit colors
R_Init_color8_translate(RGBA_t * palette)3066 void R_Init_color8_translate ( RGBA_t * palette )
3067 {
3068 int i;
3069
3070 // [WDJ] unconditional now, palette flashes etc.
3071 {
3072 for (i=0;i<256;i++)
3073 {
3074 // use palette after gamma modified
3075 register byte r = palette[i].s.red;
3076 register byte g = palette[i].s.green;
3077 register byte b = palette[i].s.blue;
3078 switch( vid.drawmode )
3079 {
3080 #ifdef ENABLE_DRAW15
3081 case DRAW15: // 15 bpp (5,5,5)
3082 color8.to16[i] = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
3083 break;
3084 #endif
3085 #ifdef ENABLE_DRAW16
3086 case DRAW16: // 16 bpp (5,6,5)
3087 color8.to16[i] = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
3088 break;
3089 #endif
3090 #ifdef ENABLE_DRAW24
3091 case DRAW24:
3092 {
3093 // different alignment from DRAW32, for speed
3094 pixelunion32_t c32;
3095 c32.pix24.r = r;
3096 c32.pix24.g = g;
3097 c32.pix24.b = b;
3098 color8.to32[i] = c32.ui32;
3099 }
3100 break;
3101 #endif
3102 #ifdef ENABLE_DRAW32
3103 case DRAW32:
3104 {
3105 pixelunion32_t c32;
3106 c32.pix32.r = r;
3107 c32.pix32.g = g;
3108 c32.pix32.b = b;
3109 c32.pix32.alpha = 0xFF;
3110 color8.to32[i] = c32.ui32;
3111 }
3112 break;
3113 #endif
3114 default:
3115 break; // should not be calling
3116 }
3117 }
3118 }
3119
3120 }
3121 #endif
3122
3123 #ifdef ENABLE_DRAW8_USING_12
3124 //#define COLOR12_QUALITY_CHECK
3125 // covert 8 bit colors
R_Init_color12_translate(RGBA_t * palette)3126 void R_Init_color12_translate ( RGBA_t * palette )
3127 {
3128 unsigned int i;
3129
3130 #ifdef COLOR12_QUALITY_CHECK
3131 printf(" color12 quality check:\n" );
3132 #endif
3133
3134 // Fill table
3135 for( i=0; i <= 0x0FFF; i++ )
3136 {
3137 // 12 bit color is R,G,B 4 bits each.
3138 // Must shift 4 bit color up to be 8 bit color;
3139 register byte r = ((i & 0x0F00) >> 4) + 0x08;
3140 register byte g = ((i & 0x00F0) ) + 0x08;
3141 register byte b = ((i & 0x000F) << 4) + 0x08;
3142 color12_to_8[i] = NearestColor( r, g, b );
3143
3144 #ifdef COLOR12_QUALITY_CHECK
3145 unsigned int b1 = ((i << 4) & 0xF0);
3146 unsigned int g1 = ((i ) & 0xF0);
3147 unsigned int r1 = ((i >> 4) & 0xF0);
3148 register RGBA_t p = pLocalPalette[ color12_to_8[i] ];
3149 unsigned int er = (abs( b1 - p.s.blue ) + abs( g1 - p.s.green ) + abs( r1 - p.s.red )) * 100 / 255; // 0 to 300%
3150 if( ( abs( b1 - p.s.blue ) > 0x3F )
3151 || ( abs( g1 - p.s.green ) > 0x3F )
3152 || ( abs( r1 - p.s.red ) > 0x3F )
3153 || ( er > 99) )
3154 {
3155 printf(" color12_translate[%4i]: (%2X,%2X,%2X) ==> (%2X,%2X,%2X) ERROR= %4i\n", i, r1,g1,b1, p.s.red,p.s.green,p.s.blue, er );
3156 }
3157 #endif
3158 }
3159 }
3160 #endif
3161
3162
3163 typedef struct
3164 {
3165 byte alpha; // 0..255
3166 byte opaque, clear; // 0..100
3167 } translucent_subst_info_t;
3168
3169 // From analyze of std translucent maps (with adjustments)
3170 static translucent_subst_info_t translucent_subst[] =
3171 {
3172 {131, 2, 0}, // TRANSLU_med
3173 {62, 0, 4}, // TRANSLU_more
3174 {60, 1, 22}, // TRANSLU_hi
3175 {140, 11, 0}, // TRANSLU_fire
3176 {200, 71, 3}, // TRANSLU_fx1
3177 {182, 0, 0} // TRANSLU_75
3178 };
3179
3180
3181 //#define VIEW_TRANSLUMAP_GEN
3182 //#define VIEW_TRANSLUMAP_GEN_DETAIL
3183
3184 // [WDJ] Analyze a Boom Translucent Map to derive some GL parameters
R_TranslucentMap_Analyze(translucent_map_t * transp,byte * tmap)3185 void R_TranslucentMap_Analyze( translucent_map_t * transp, byte * tmap )
3186 {
3187 // Analyze the Boom translucent map for rgb drawing.
3188 byte * tstcolor = & doom_analyze_index[0]; // colors to test
3189 int ti;
3190
3191 if( EN_heretic )
3192 tstcolor = & heretic_analyze_index[0]; // heretic colors to test
3193
3194 float h4 = 0.0; // alpha = 0
3195 int alpha;
3196 int tot_cnt = 0;
3197 int opaque_cnt = 0;
3198 int clear_cnt = 0;
3199 int dd4, dn4, k1, k2;
3200 // tm3 = i1 * (1-alpha) + i2 * alpha
3201 // alpha = (i1-tm3) / (i1-i2)
3202 for( k1=0; k1<NUM_ANALYZE_COLORS; k1++ )
3203 {
3204 byte i1 = tstcolor[k1]; // background
3205 for( k2=0; k2<NUM_ANALYZE_COLORS; k2++ )
3206 {
3207 if( k1 == k2 ) continue;
3208 byte i2 = tstcolor[k2]; // translucent
3209 byte tm3 = tmap[ (i2<<8) + i1 ];
3210 // for each color
3211 int krgb;
3212 #ifdef VIEW_TRANSLUMAP_GEN_DETAIL
3213 GenPrintf(EMSG_info, "bg(%i,%i,%i):fb(%i,%i,%i):>(%i,%i,%i) ",
3214 pLocalPalette[i1].s.red,pLocalPalette[i1].s.green,pLocalPalette[i1].s.blue,
3215 pLocalPalette[i2].s.red,pLocalPalette[i2].s.green,pLocalPalette[i2].s.blue,
3216 pLocalPalette[tm3].s.red,pLocalPalette[tm3].s.green,pLocalPalette[tm3].s.blue
3217 );
3218 #endif
3219 for( krgb=0; krgb<3; krgb++ ) // red, green, blue
3220 {
3221 // alpha = (i1-tm3) / (i1-i2)
3222 switch( krgb )
3223 {
3224 case 0: // red
3225 dd4 = (int)pLocalPalette[i1].s.red - (int)pLocalPalette[i2].s.red;
3226 dn4 = (int)pLocalPalette[i1].s.red - (int)pLocalPalette[tm3].s.red;
3227 break;
3228 case 1: // green
3229 dd4 = (int)pLocalPalette[i1].s.green - (int)pLocalPalette[i2].s.green;
3230 dn4 = (int)pLocalPalette[i1].s.green - (int)pLocalPalette[tm3].s.green;
3231 break;
3232 default: // blue
3233 dd4 = (int)pLocalPalette[i1].s.blue - (int)pLocalPalette[i2].s.blue;
3234 dn4 = (int)pLocalPalette[i1].s.blue - (int)pLocalPalette[tm3].s.blue;
3235 break;
3236 }
3237 // eliminate cases where equation is least accurate
3238 if( dn4 && (dd4 > 10.0 || dd4 < -10.0))
3239 {
3240 float h3 = (float)dn4 / (float)dd4;
3241 #ifdef VIEW_TRANSLUMAP_GEN_DETAIL
3242 GenPrintf(EMSG_info, " %i", (int)(h3*255) );
3243 #endif
3244 // eliminate wierd alpha (due to color quantization in making the transmap)
3245 if( h3 > 0.0 && h3 < 1.1 )
3246 {
3247 h4 += h3; // total for avg
3248 tot_cnt ++;
3249 if( h3 > 0.9 ) opaque_cnt++;
3250 if( h3 < 0.1 ) clear_cnt++;
3251 }
3252 }
3253 #ifdef VIEW_TRANSLUMAP_GEN_DETAIL
3254 else
3255 {
3256 GenPrintf(EMSG_info, " -" );
3257 }
3258 #endif
3259 }
3260 #ifdef VIEW_TRANSLUMAP_GEN_DETAIL
3261 GenPrintf(EMSG_info,"\n");
3262 #endif
3263 }
3264 }
3265 alpha = (int) (255.0 * h4 / tot_cnt);
3266 if( alpha > 255 ) alpha = 255;
3267 if( alpha < 0 ) alpha = 0;
3268 transp->alpha = alpha;
3269 transp->opaque = (opaque_cnt*100)/tot_cnt;
3270 transp->clear = (clear_cnt*100/tot_cnt);
3271 transp->substitute_std_translucent = TRANSLU_med; // default
3272 transp->substitute_error = 255;
3273 {
3274 // find closest standard transparency
3275 float bestdist = 1E20;
3276 for(ti=1; ti<TRANSLU_75; ti++)
3277 {
3278 translucent_subst_info_t * tinfop = & translucent_subst[ti-1];
3279 float dista = tinfop->alpha - alpha; // 0..255
3280 float distop = tinfop->opaque - transp->opaque; // 0..100
3281 float distcl = tinfop->clear - transp->clear; // 0..100
3282 float dist = (dista*dista) + (distop*distop) + (distcl*distcl);
3283 if( dist < bestdist )
3284 {
3285 bestdist = dist;
3286 dist *= (255.0/(40.0*40.0 + 20.0*20.0 + 10.0*10.0));
3287 if( dist > 255 ) dist = 255;
3288 transp->substitute_error = dist;
3289 transp->substitute_std_translucent = ti;
3290 }
3291 }
3292 }
3293 #ifdef VIEW_TRANSLUMAP_GEN
3294 // Enable to see results of analysis.
3295 GenPrintf(EMSG_info,
3296 "Analyze Trans: alpha=%i opaque=%i%% clear=%i%% subst=%i subst_err=%i\n",
3297 alpha, transp->opaque, transp->clear,
3298 transp->substitute_std_translucent, transp->substitute_error);
3299 #endif
3300 }
3301
3302 #define TRANSLU_STORE_INC 8
3303 translucent_map_t * translu_store = NULL;
3304 int translu_store_num = 0;
3305 int translu_store_len = 0;
3306
3307 // Return translu_store index
R_setup_translu_store(int lump_num)3308 int R_setup_translu_store( int lump_num )
3309 {
3310 int ti;
3311 translucent_map_t * tranlu_map;
3312 // check if already in store
3313 for(ti=0; ti< translu_store_num; ti++ )
3314 {
3315 if( translu_store[ti].translu_lump_num == lump_num )
3316 goto done;
3317 }
3318 // check for expand store
3319 if( translu_store_num >= translu_store_len )
3320 {
3321 translu_store_len += TRANSLU_STORE_INC;
3322 translu_store = realloc( translu_store, translu_store_len );
3323 if( translu_store == NULL )
3324 I_Error( "Translucent Store: cannot alloc\n" );
3325 }
3326 // create new store and fill it in
3327 ti = translu_store_num++;
3328 tranlu_map = & translu_store[ti];
3329 tranlu_map->translu_lump_num = lump_num;
3330 R_TranslucentMap_Analyze( tranlu_map, W_CacheLumpNum( lump_num, PU_CACHE ) );
3331 if( verbose>1 )
3332 GenPrintf(EMSG_ver, "TRANSLU STORE lump=%i, subst=%i\n", lump_num, tranlu_map->substitute_std_translucent );
3333 done:
3334 return ti;
3335 }
3336
3337 #if 0
3338 // [WDJ] Only enable to setup colormap analyze tables
3339 #define ANALYZE_GAMEMAP
3340 void Analyze_gamemap( void )
3341 {
3342 #define NUMTESTCOLOR 8
3343 // For new port, analyze the colormap to find white, grey, red, blue, green.
3344 // This only affects this color analyzer, and is not fatal.
3345 static const char * name[NUMTESTCOLOR]=
3346 {"white", "light grey", "med grey", "dark grey", "grayblack", "red", "green", "blue" };
3347 typedef struct { byte red, green, blue; } test_rgb_t;
3348 static const test_rgb_t ideal[NUMTESTCOLOR]=
3349 {{255,255,255}, {192,192,192}, {128,128,128}, {64,64,64}, {10,10,10}, {100,0,0}, {0,100,0}, {0,0,100} };
3350 float bestdist[NUMTESTCOLOR];
3351 byte bestcolor[NUMTESTCOLOR];
3352 int i, k;
3353
3354 GenPrintf(EMSG_info, "Game colormap analyze:\n" );
3355 for(k=0; k<8; k++ ) bestdist[k] = 1E20;
3356
3357 for(i=0; i<256; i++)
3358 {
3359 int cr = pLocalPalette[i].s.red;
3360 int cg = pLocalPalette[i].s.green;
3361 int cb = pLocalPalette[i].s.blue;
3362 for(k=0; k<NUMTESTCOLOR; k++ )
3363 {
3364 float dr = cr - ideal[k].red;
3365 float dg = cg - ideal[k].green;
3366 float db = cb - ideal[k].blue;
3367 float d = dr*dr + dg*dg + db*db;
3368 if( d < bestdist[k] )
3369 {
3370 bestdist[k] = d;
3371 bestcolor[k] = i;
3372 }
3373 }
3374 }
3375 for(k=0; k<NUMTESTCOLOR; k++ )
3376 {
3377 GenPrintf(EMSG_info, "Analyze Index %s = %i\n", name[k], bestcolor[k] );
3378 }
3379 }
3380 #endif
3381
3382 #if 0
3383 // [WDJ] Only enable to setup translucent analyze tables
3384 #define ANALYZE_TRANSLUCENT_MAPS
3385 void Analyze_translucent_maps( void )
3386 {
3387 // translucent maps
3388 translucent_map_t trans;
3389 int k;
3390 GenPrintf(EMSG_info, "Game translucent maps analyze:\n" );
3391 if( translucenttables == NULL ) return;
3392 for(k=1; k<=TRANSLU_fx1; k++ ) // Doom2 maps
3393 {
3394 byte * tmap = & translucenttables[ TRANSLU_TABLE_INDEX(k) ];
3395 if( tmap )
3396 {
3397 GenPrintf(EMSG_info, " Analyze translucent map %i:\n", k );
3398 R_TranslucentMap_Analyze( &trans, tmap);
3399 }
3400 }
3401 }
3402 #endif
3403
3404
3405 // Table of alpha = 0..255 to translucent tables to be used for r_draw8
3406 // For use by DRAW8PAL, Not for draw modes that can use dr_alpha.
3407 // index by alpha >> 4
3408 const unsigned int translucent_alpha_table[16] =
3409 {
3410 // hi=10..15%, more=20..25%, med=50%
3411 TRANSLU_TABLE_hi, // 0..15 ( 0.. 6%)
3412 TRANSLU_TABLE_hi, // 16..31 ( 6..12%)
3413 TRANSLU_TABLE_hi, // 32..47 (12..18%)
3414 TRANSLU_TABLE_more, // 48..63 (18..25%)
3415 TRANSLU_TABLE_more, // 64..79 (25..31%)
3416 TRANSLU_TABLE_more, // 80..95 (31..37%)
3417 TRANSLU_TABLE_med, // 96..111 (37..43%)
3418 TRANSLU_TABLE_med, // 112..127 (44..50%)
3419 TRANSLU_TABLE_med, // 128..143 (50..56%)
3420 // reversed table usage, per TRANSLU_REV_ALPHA
3421 TRANSLU_TABLE_med, // 144..159 (56..62%)
3422 TRANSLU_TABLE_more, // 160..177 (63..69%)
3423 TRANSLU_TABLE_more, // 176..191 (69..75%)
3424 TRANSLU_TABLE_more, // 192..207 (75..81%)
3425 TRANSLU_TABLE_hi, // 208..223 (81..87%)
3426 TRANSLU_TABLE_hi, // 224..239 (88..93%)
3427 TRANSLU_TABLE_hi, // 240..255 (94..100%)
3428 };
3429
3430
3431
3432 // Fake floor fog and water effect structure
3433 #define FWE_STORE_INC 16
3434 fogwater_t * fweff = NULL; // array
3435 // 0 of the array is not used
3436 static int fweff_num = 0;
3437 static int fweff_len = 0; // num allocated
3438
R_get_fweff(void)3439 int R_get_fweff( void )
3440 {
3441 // check for expand store
3442 if( fweff_num >= fweff_len )
3443 {
3444 fweff_len += FWE_STORE_INC;
3445 fweff = (fogwater_t*) realloc( fweff, fweff_len * sizeof(fogwater_t) );
3446 if( fweff == NULL )
3447 I_Error( "Fog Store: cannot alloc\n" );
3448 }
3449 memset( &fweff[fweff_num], 0, sizeof( fogwater_t ) );
3450 return fweff_num++;
3451 }
3452
3453
3454 // update config settings
R_FW_config_update(void)3455 void R_FW_config_update( void )
3456 {
3457 int i;
3458 // If not init yet, then init will call this again
3459 if( ! fweff )
3460 return;
3461
3462 // defaults affected by controls
3463 fweff[1].effect = (fogwater_effect_e) cv_water_effect.value;
3464 fweff[2].effect = (fogwater_effect_e) cv_fog_effect.value;
3465 fweff[3].effect = fweff[1].effect;
3466 // update all fweff settings that were defaulted
3467 for( i=5; i<fweff_num; i++ )
3468 {
3469 byte fwf = fweff[i].flags;
3470 fogwater_t * def = & fweff[ fwf & FWF_index ];
3471 if( fwf & FWF_default_effect )
3472 {
3473 fweff[i].effect = def->effect;
3474 }
3475 if( fwf & FWF_default_alpha )
3476 {
3477 fweff[i].alpha = def->alpha;
3478 fweff[i].fsh_alpha = def->fsh_alpha;
3479 }
3480 }
3481 // Must also change the affected FakeFloor flags
3482 P_Config_FW_Specials ();
3483 }
3484
3485 // start of level
R_Clear_FW_effect(void)3486 void R_Clear_FW_effect( void )
3487 {
3488 if( ! fweff ) // no memory yet
3489 {
3490 // init
3491 R_get_fweff(); // [0] unused
3492 R_get_fweff(); // [1] water
3493 R_get_fweff(); // [2] fog
3494 R_get_fweff(); // [3] opaque water
3495 R_get_fweff(); // [4] solid floor
3496 fweff[0].effect = FW_clear; // unused
3497 fweff[0].alpha = 0;
3498 fweff[0].fsh_alpha = 0;
3499 fweff[0].flags = 0;
3500 fweff[1].effect = FW_clear;
3501 fweff[1].alpha = 128; // default water alpha
3502 fweff[1].fsh_alpha = 128;
3503 fweff[1].flags = FWF_water | FWF_default_alpha | FWF_default_effect;
3504 fweff[2].effect = FW_fogdust;
3505 fweff[2].alpha = 110; // default fog alpha
3506 fweff[2].fsh_alpha = 110 * 0.90;
3507 fweff[2].flags = FWF_fog | FWF_default_alpha | FWF_default_effect;
3508 fweff[3].effect = FW_clear;
3509 fweff[3].alpha = 190; // default opaque water
3510 fweff[3].fsh_alpha = 190;
3511 fweff[3].flags = FWF_opaque_water | FWF_default_alpha | FWF_default_effect;
3512 fweff[4].effect = FW_clear; // does not matter
3513 fweff[4].alpha = 128; // default solid translucent floor
3514 fweff[4].fsh_alpha = 128;
3515 fweff[4].flags = FWF_solid_floor; // not settable defaults
3516 R_FW_config_update(); // config settings
3517 }
3518 fweff_num = 5; // only save the defaults
3519 }
3520
3521
3522 // Create Fog Effect from texture name string
3523 // Syntax: #aaaN
3524 // where aaa is alpha, in decimal, 0..255
3525 // where N is fog_effect, from this table
3526 fogwater_effect_e fwe_code_table[FW_num] =
3527 {
3528 FW_clear, // 'A' no fog (old WATER default)
3529 FW_cast, // 'B' paint all surfaces with textures
3530 FW_colormap, // 'C' use colormap fog (which only colors all sectors)
3531 FW_inside, // 'D' render inside side, plane views (old FOG)
3532 FW_foglite, // 'E' outside side, plane views, low alpha overall fog sheet
3533 FW_fogdust, // 'F' outside, when in fog apply overall fog sheet (FOG default)
3534 FW_fogsheet, // 'G' outside, overall fog sheet, sector join fog sheet
3535 FW_fogfluid, // 'H' outside, inside fluid, fogsheet
3536 };
3537
3538
3539 // return index into fweff
R_Create_FW_effect(int special_linedef,char * tstr)3540 int R_Create_FW_effect( int special_linedef, char * tstr )
3541 {
3542 int def_index = // of fweff[]
3543 ( special_linedef == 304 )? FWF_opaque_water // opaque water
3544 : ( special_linedef == 302 )? FWF_fog // fog
3545 : ( special_linedef == 301 )? FWF_water // water
3546 : ( special_linedef == 300 )? FWF_solid_floor // solid floor
3547 : 0;
3548 int fwe_index;
3549 byte wflags = 0;
3550 fogwater_t * fwp;
3551
3552 if( tstr[0] != '#' )
3553 {
3554 return def_index; // can use a default
3555 }
3556 // make a unique entry for this situation
3557 fwe_index = R_get_fweff();
3558 fwp = &fweff[fwe_index];
3559 fwp->effect = fweff[def_index].effect; // get default settings
3560 fwp->alpha = fweff[def_index].alpha;
3561 wflags = fweff[def_index].flags;
3562
3563 if( tstr[0] == '#') // decode upper texture string
3564 {
3565 // alpha
3566 fwp->alpha = CHAR_TO_INT(tstr[1])*100 + CHAR_TO_INT(tstr[2])*10 + CHAR_TO_INT(tstr[3]);
3567 wflags &= ~ FWF_default_alpha;
3568 // fog type
3569 char chf = tstr[4];
3570 if( chf >= 'A' && chf <= ('A'+FW_num) )
3571 {
3572 fwp->effect = fwe_code_table[ chf - 'A' ];
3573 wflags &= ~ FWF_default_effect;
3574 }
3575 }
3576 if( special_linedef == 300 ) // FWF_solid_floor
3577 {
3578 fwp->effect = FW_clear; // no internal fog effect
3579 }
3580 switch( fwp->effect )
3581 {
3582 case FW_foglite:
3583 fwp->fsh_alpha = fwp->alpha * 0.60;
3584 break;
3585 case FW_fogdust:
3586 fwp->fsh_alpha = fwp->alpha * 0.90;
3587 break;
3588 case FW_fogsheet:
3589 fwp->fsh_alpha = fwp->alpha * 0.80;
3590 break;
3591 case FW_fogfluid:
3592 default:
3593 fwp->fsh_alpha = fwp->alpha;
3594 break;
3595 }
3596 fwp->flags = wflags;
3597 return fwe_index;
3598 }
3599
3600
3601 // R_Load_Data
3602 // Locates all the lumps that will be used by all views
3603 // Must be called after W_Init.
3604 //
R_Load_Data(void)3605 void R_Load_Data (void)
3606 {
3607 CONS_Printf ("\nLoad Textures...");
3608 R_Load_Textures ();
3609 CONS_Printf ("\nLoad Flats...");
3610 R_Load_Flats ();
3611
3612 CONS_Printf ("\nInitSprites...\n");
3613 R_Init_SpriteLumps ();
3614 R_Init_Sprites (sprnames);
3615
3616 CONS_Printf ("\nLoad Colormaps...\n");
3617 R_Load_Colormaps ();
3618 #ifdef ANALYZE_GAMEMAP
3619 Analyze_gamemap();
3620 #endif
3621 }
3622
3623
3624 //
3625 // R_CheckTextureNumForName
3626 // Check whether texture is available.
3627 // Filter out NoTexture indicator.
3628 //
3629 // [WDJ] Original Doom bug: conflict between texture[0] and 0=no-texture.
3630 //
3631 // Parameter name is 8 char without term.
3632 // Return -1 for not found, 0 for no texture
R_CheckTextureNumForName(const char * name)3633 int R_CheckTextureNumForName (const char *name)
3634 {
3635 int i;
3636
3637 // "NoTexture" marker.
3638 if (name[0] == '-')
3639 return 0;
3640
3641 for (i=FIRST_TEXTURE ; i<numtextures ; i++)
3642 if (!strncasecmp (textures[i]->name, name, 8) )
3643 return i;
3644 #ifdef RANGECHECK
3645 if( i == 0 )
3646 GenPrintf(EMSG_warn, "Texture %8.8s is texture[0], imitates no-texture.\n", name);
3647 #endif
3648
3649 return -1;
3650 }
3651
3652
3653
3654 //
3655 // R_TextureNumForName
3656 // Calls R_CheckTextureNumForName,
3657 //
3658 // Return 0 for no texture "-".
3659 // Return default texture when texture not found (would HOM otherwise).
3660 // Parameter name is 8 char without term.
3661 // Is used for side_t texture fields, which are used for array access
3662 // without further error checks, so never returns -1.
R_TextureNumForName(const char * name)3663 int R_TextureNumForName (const char* name)
3664 {
3665 int i;
3666
3667 i = R_CheckTextureNumForName (name);
3668 #if 0
3669 // [WDJ] DEBUG TRACE, to see where textures have ended up and which are accessed.
3670 # define trace_SIZE 512
3671 static char debugtrace_RTNFN[ trace_SIZE ];
3672 if( i<trace_SIZE && debugtrace_RTNFN[i] != 0x55 ) {
3673 debug_Printf( "Texture %8.8s is texture[%i]\n", name, i);
3674 debugtrace_RTNFN[i] = 0x55;
3675 }
3676 # undef trace_SIZE
3677 #endif
3678
3679 if(i==-1)
3680 {
3681 // Exclude # parameters from "not found" message.
3682 // Prevent warning due to using signed char as index
3683 if( isalpha((unsigned char) name[0]) )
3684 I_SoftError("R_TextureNumForName: %.8s not found\n", name);
3685
3686 i=1; // default to texture[1]
3687 }
3688 return i;
3689 }
3690
3691
3692
3693
3694 //
3695 // R_PrecacheLevel
3696 // Preloads all relevant graphics for the level.
3697 //
3698
R_PrecacheLevel(void)3699 void R_PrecacheLevel (void)
3700 {
3701 char* texturepresent;
3702 char* spritepresent;
3703
3704 int i,j,k,n;
3705 lumpnum_t lumpnum;
3706
3707 thinker_t* th;
3708 spriteframe_t * sf;
3709 sprite_frot_t * sv;
3710
3711 //int numgenerated; //faB:debug
3712
3713 if (demoplayback)
3714 return;
3715
3716 // do not flush the memory, Z_Malloc twice with same user
3717 // will cause error in Z_CheckHeap(), 19991022 by Kin
3718 if (rendermode != render_soft)
3719 return;
3720
3721 // Precache flats.
3722 flatmemory = P_PrecacheLevelFlats();
3723
3724 //
3725 // Precache textures.
3726 //
3727 // no need to precache all software textures in 3D mode
3728 // (note they are still used with the reference software view)
3729 texturepresent = calloc(numtextures,sizeof(char)); // temp alloc, zeroed
3730
3731 for (i=0 ; i<numsides ; i++)
3732 {
3733 // for all sides
3734 // texture num 0=no-texture, otherwise is valid texture
3735 #if 1
3736 if (sides[i].toptexture)
3737 texturepresent[sides[i].toptexture] = 1;
3738 if (sides[i].midtexture)
3739 texturepresent[sides[i].midtexture] = 1;
3740 if (sides[i].bottomtexture)
3741 texturepresent[sides[i].bottomtexture] = 1;
3742 #else
3743 //Hurdler: huh, a potential bug here????
3744 if (sides[i].toptexture < numtextures)
3745 texturepresent[sides[i].toptexture] = 1;
3746 if (sides[i].midtexture < numtextures)
3747 texturepresent[sides[i].midtexture] = 1;
3748 if (sides[i].bottomtexture < numtextures)
3749 texturepresent[sides[i].bottomtexture] = 1;
3750 #endif
3751 }
3752
3753 #if 0
3754 // Sky texture is always present.
3755 // Note that F_SKY1 is the name used to
3756 // indicate a sky floor/ceiling as a flat,
3757 // while the sky texture is stored like
3758 // a wall texture, with an episode dependent name.
3759 texturepresent[sky_texture] = 1;
3760 #endif
3761
3762 //if (devparm)
3763 // GenPrintf(EMSG_dev, "Generating textures..\n");
3764
3765 texturememory = 0; // global
3766 for (i=FIRST_TEXTURE ; i<numtextures ; i++)
3767 {
3768 if (!texturepresent[i])
3769 continue;
3770
3771 //texture = textures[i];
3772 if( texture_render[i].cache == NULL )
3773 R_GenerateTexture2 ( i, &texture_render[i], TM_none );
3774 //numgenerated++;
3775
3776 // note: pre-caching individual patches that compose textures became
3777 // obsolete since we now cache entire composite textures
3778 }
3779 //debug_Printf("total mem for %d textures: %d k\n",numgenerated,texturememory>>10);
3780 free(texturepresent);
3781
3782 //
3783 // Precache sprites.
3784 //
3785 spritepresent = calloc(numsprites,sizeof(char)); // temp alloc, zeroed
3786
3787 for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
3788 {
3789 if (th->function.acp1 == (actionf_p1)P_MobjThinker)
3790 spritepresent[((mobj_t *)th)->sprite] = 1;
3791 }
3792
3793 spritememory = 0;
3794 for (i=0 ; i<numsprites ; i++)
3795 {
3796 if (!spritepresent[i])
3797 continue;
3798
3799 for (j=0 ; j<sprites[i].numframes ; j++)
3800 {
3801 sf = get_spriteframe( &sprites[i], j );
3802 n = srp_to_num_rot[ sf->rotation_pattern ];
3803 for (k=0 ; k<n ; k++)
3804 {
3805 sv = get_framerotation( &sprites[i], j, k );
3806 //Fab: see R_Init_Sprites for more about pat_lumpnum,lumpid
3807 lumpnum = sv->pat_lumpnum;
3808 if(devparm)
3809 spritememory += W_LumpLength(lumpnum);
3810 W_CachePatchNum( lumpnum, PU_CACHE );
3811 }
3812 }
3813 }
3814 free(spritepresent);
3815
3816 //FIXME: this is no more correct with glide render mode
3817 if (devparm)
3818 {
3819 GenPrintf(EMSG_dev,
3820 "Precache level done:\n"
3821 "flatmemory: %ld k\n"
3822 "texturememory: %ld k\n"
3823 "spritememory: %ld k\n", flatmemory>>10, texturememory>>10, spritememory>>10 );
3824 }
3825 #ifdef ANALYZE_TRANSLUCENT_MAPS
3826 // maps are loaded by now
3827 Analyze_translucent_maps();
3828 #endif
3829 }
3830
3831
R_Init_rdata(void)3832 void R_Init_rdata(void)
3833 {
3834 int i;
3835
3836 // clear for easier debugging
3837 memset(extra_colormaps, 0, sizeof(extra_colormaps));
3838
3839 for(i = 0; i < MAXCOLORMAPS; i++)
3840 {
3841 extra_colormap_lumpnum[i] = NO_LUMP;
3842 extra_colormaps[i].colormap = NULL;
3843 }
3844 }
3845
3846 // Upon change in rendermode.
R_rdata_setup_rendermode(void)3847 void R_rdata_setup_rendermode( void )
3848 {
3849 int i;
3850
3851 // Colormaps are depedent upon rendermode.
3852 for( i=0; i<num_extra_colormaps; i++ )
3853 {
3854 if( VALID_LUMP( extra_colormap_lumpnum[i] ) )
3855 {
3856 // Analyze the lump
3857 R_Colormap_Analyze( i );
3858 }
3859 else
3860 {
3861 // Create from parameters
3862 R_Create_Colormap_ex( & extra_colormaps[i] );
3863 }
3864 }
3865 }
3866