1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: r:/prj/cit/src/RCS/textmaps.c $
21  * $Revision: 1.77 $
22  * $Author: xemu $
23  * $Date: 1994/11/21 17:38:46 $
24  */
25 
26 #define __TEXTMAPS_SRC
27 
28 #include <string.h>
29 
30 #include "ShockDialogs.h"
31 
32 #include "textmaps.h"
33 #include "gettmaps.h"
34 #include "tools.h"
35 #include "frprotox.h"
36 #include "cybmem.h"
37 #include "criterr.h"
38 #include "citres.h"
39 #include "rendtool.h"
40 #include "objects.h"
41 #include "objstuff.h"
42 #include "tpolys.h"
43 #include "statics.h"
44 
45 #include "OpenGL.h"
46 
47 //#include <mprintf.h>
48 //#include <dpaths.h>
49 //#include <config.h>
50 //#include <_gfx.h>
51 //#include <_system.h>
52 //#include <_lg.h>
53 
54 uchar textures_loaded = FALSE;
55 
56 #define READ(fd, x) read(fd, (char *)&(x), sizeof(x))
57 
58 Id tmap_ids[NUM_TEXTURE_SIZES] = {TEXTURE_128_ID, TEXTURE_64_ID, TEXTURE_32_ID, TEXTURE_16_ID};
59 ushort tmap_sizes[NUM_TEXTURE_SIZES] = {128, 64, 32, 16};
60 uchar all_textures = TRUE;
61 
62 extern uchar tmap_big_buffer[];
63 
64 // prototypes
65 uchar set_animations(short start, short frames, uchar *anim_used);
66 errtype load_small_texturemaps(void);
67 void setup_tmap_bitmaps(void);
68 void free_textures(void);
69 errtype load_master_texture_properties(void);
70 errtype unload_master_texture_properties(void);
71 errtype clear_texture_properties(void);
72 errtype texture_crunch_init(void);
73 errtype texture_crunch_go(void);
74 void load_textures(void);
75 
76 extern void FlipShort(short *sh);
77 extern void FlipLong(long *lng);
78 
79 #define SET_ANIM_USED(x) anim_used[(x) >> 3] |= (1 << ((x)&0x7))
80 #define CHECK_ANIM_USED(x) anim_used[(x) >> 3] & (1 << ((x)&0x7))
81 
82 #define ACTUAL_SMALL_ANIMS 101
set_animations(short start,short frames,uchar * anim_used)83 uchar set_animations(short start, short frames, uchar *anim_used) {
84     int loop;
85     // Note that NUM_ACTUAL_SMALL_ANIMS contains the actual number of valid
86     // animations, BUT anything in the gap between them will get caught by the
87     // ResInUse call in load_small_texturemaps
88     if ((start < 0) || (start + frames > MAX_SMALL_TMAPS)) {
89         //      mprintf("PAIN SUFFERING SET ANIM DEATH %d %d\n",start,frames);
90         return FALSE;
91     }
92     for (loop = start; loop < start + frames; loop++)
93         SET_ANIM_USED(loop);
94     return TRUE;
95 }
96 
load_small_texturemaps(void)97 errtype load_small_texturemaps(void) {
98     Id id = TEXTURE_SMALL_ID;
99     char i = 0;
100     extern uchar obj_is_display(int triple);
101     int d;
102     char rv = 0;
103     ObjSpecID osid;
104     uchar anim_used[MAX_SMALL_TMAPS / 8];
105 
106     LG_memset(anim_used, 0, MAX_SMALL_TMAPS / 8);
107 
108     // Figure out which animations are in use
109     osid = objBigstuffs[0].id;
110     while (osid != OBJ_SPEC_NULL) {
111         if (obj_is_display(ID2TRIP(objBigstuffs[osid].id))) { //was objSmallstuffs
112             d = objBigstuffs[osid].data2;
113             if ((d & TPOLY_INDEX_MASK) && ((d & TPOLY_TYPE_MASK) == 0x100))
114                 rv = set_animations(d & TPOLY_INDEX_MASK, objBigstuffs[osid].cosmetic_value, anim_used);
115             if (((d >> 16) & TPOLY_INDEX_MASK) && ((d & TPOLY_TYPE_MASK) == 0x100))
116                 rv |= set_animations((d >> 16) & TPOLY_INDEX_MASK, objBigstuffs[osid].cosmetic_value, anim_used);
117             //         if (!rv) mprintf("Big badness for o %x, osid %x, data2 %d\n",objBigstuffs[osid].id,osid,d);
118         }
119         osid = objBigstuffs[osid].next;
120     }
121 
122     osid = objSmallstuffs[0].id;
123     while (osid != OBJ_SPEC_NULL) {
124         if (obj_is_display(ID2TRIP(objSmallstuffs[osid].id))) {
125             d = objSmallstuffs[osid].data2;
126             if ((d & TPOLY_INDEX_MASK) && ((d & TPOLY_TYPE_MASK) == 0x100))
127                 rv = (char)set_animations(d & TPOLY_INDEX_MASK, objSmallstuffs[osid].cosmetic_value, anim_used);
128             if (((d >> 16) & TPOLY_INDEX_MASK) && ((d & TPOLY_TYPE_MASK) == 0x100))
129                 rv |=
130                     (char)set_animations((d >> 16) & TPOLY_INDEX_MASK, objSmallstuffs[osid].cosmetic_value, anim_used);
131             //         if (!rv) mprintf("Small badness for o %x, osid %x, data2 %d\n",objSmallstuffs[osid].id,osid,d);
132         }
133         osid = objSmallstuffs[osid].next;
134     }
135 
136     while (ResInUse(id + i)) {
137         if (CHECK_ANIM_USED(i)) {
138             ResLock(id + i);
139             ResUnlock(id + i);
140         }
141         i++;
142     }
143     return (OK);
144 }
145 
146 // should really do dynamic creation of grs_bitmap *'s for the textures
147 // but for now, we'll be lame
148 
149 extern uchar tmap_static_mem[];
150 static uchar *tmap_dynamic_mem = NULL;
151 
152 #define get_tmap_128x128(i) ((uchar *)&tmap_dynamic_mem[i * (128 * 128)])
153 #define get_tmap_64x64(i)   ((uchar *)&tmap_static_mem[i * SIZE_STATIC_TMAP])
154 #define get_tmap_32x32(i)   ((uchar *)&tmap_static_mem[(i * SIZE_STATIC_TMAP) + (64 * 64)])
155 #define get_tmap_16x16(i)   ((uchar *)&tmap_static_mem[(i * SIZE_STATIC_TMAP) + (64 * 64) + (32 * 32)])
156 
157 // have we built the tables, do we have the extra memory, so on
158 static uchar tmaps_setup = FALSE;
159 
160 static grs_bitmap tmap_bitmaps[NUM_TEXTURE_SIZES];
setup_tmap_bitmaps(void)161 void setup_tmap_bitmaps(void) {
162     int i;
163     for (i = 0; i < 4; i++)
164         gr_init_bm(&tmap_bitmaps[i], NULL, BMT_FLAT8, 0, tmap_sizes[i], tmap_sizes[i]);
165 }
166 
get_texture_map(int idx,int sz)167 grs_bitmap *get_texture_map(int idx, int sz) {
168     ushort sz_add[NUM_TEXTURE_SIZES - 1] = {0, 64 * 64, (64 * 64) + (32 * 32)};
169     uchar *bt;
170 //   mprintf("Getting tmap %d, sz %d\n",idx,sz);
171 #ifdef DEMO
172     if (sz == 2)
173         sz = 1;
174 #endif
175     if (sz == 0) {
176         if (all_textures)
177             bt = get_tmap_128x128(idx);
178         else
179             sz = 1;
180     }
181     if (sz != 0) {
182         bt = get_tmap_64x64(idx) + sz_add[sz - 1];
183     }
184     tmap_bitmaps[sz].bits = bt;
185     return &tmap_bitmaps[sz];
186 }
187 
load_textures(void)188 void load_textures(void) {
189     grs_bitmap *cur_bm;
190     int i, n, c;
191     errtype retval = OK;
192     int atext_tmp = 1;
193 
194     {
195         if (start_mem < EXTRA_TMAP_THRESHOLD)
196             atext_tmp = 0;
197         else {
198             // Spew(DSRC_SYSTEM_Memory, ("Sufficient Memory detected for Loading 128s!\n"));
199             atext_tmp = 1;
200         }
201     }
202 
203     // Spew(DSRC_GFX_Texturemaps, ("all_textures = %d\n",all_textures));
204     all_textures = atext_tmp;
205     // Spew(DSRC_GFX_Texturemaps, ("GAME_TEXTURES = %d\n",GAME_TEXTURES));
206 
207     if (!tmaps_setup) {
208         if (all_textures) // get our butts some memory
209             tmap_dynamic_mem = tmap_big_buffer;
210 
211         setup_tmap_bitmaps();
212         tmaps_setup = TRUE;
213     }
214 
215     for (c = 0; c < NUM_LOADED_TEXTURES; c++) {
216         i = loved_textures[c];
217         if (!ResInUse(TEXTURE_64_ID + i)) {
218             // Warning(("Hey, invalid texture in palette! slot %d = %d\n",c,i));
219             i = 0;
220         } // Set local properties
221         for (n = SMALLEST_SIZE_INDEX; n < NUM_TEXTURE_SIZES; n++) {
222             if ((n != TEXTURE_128_INDEX) || all_textures) {
223 #ifdef DEMO
224                 if (n == TEXTURE_32_INDEX)
225                     break;
226 #endif
227                 cur_bm = get_texture_map(c, n);
228 
229                 // This is a BLATANT hack to get around the 1 Meg limit in the resource system
230                 if ((n == TEXTURE_128_INDEX) || (n == TEXTURE_64_INDEX)) {
231                     if (ResInUse(tmap_ids[n] + i)) {
232                         retval = load_res_bitmap(cur_bm, MKREF(tmap_ids[n] + i, 0), FALSE);
233                         cur_bm->flags = 0;
234                     } else {
235                         // Warning(("Hey, ResInUse failed in tmap_load and i'm so blue
236                         // (%d,%d,%x)\n",n,i,tmap_ids[n]+i));
237                         // should abort !!!
238                     }
239                 } else {
240                     retval = load_res_bitmap(cur_bm, MKREF(tmap_ids[n], i), FALSE);
241                     cur_bm->flags = 0;
242                 }
243                 if ((cur_bm->w != tmap_sizes[n]) || (cur_bm->h != tmap_sizes[n])) {
244                     // Warning(("Incorrect size in tmap %d! (%d)(%d x %d) vs (%d x %d)\n",i,c,cur_bm->w,
245                     //   cur_bm->h, tmap_sizes[n], tmap_sizes[n]));
246                     // should abort !!!
247                     //               DBG(DSRC_GFX_Texturemaps, {
248                     //                              gr_set_fcolor(0);
249                     //                              gr_rect(0,0,320,200);
250                     //                              gr_bitmap(cur_bm, 0, 0);
251                     //               });
252                 }
253                 if(can_use_opengl())
254                     opengl_cache_wall_texture(c, n, cur_bm);
255             }
256         }
257     }
258     // Load in texture properties for all textures
259     load_master_texture_properties();
260 
261     // Copy the appropriate things into textprops
262     for (i = 0; i < NUM_LOADED_TEXTURES; i++)
263         textprops[i] = texture_properties[loved_textures[i]];
264 
265     // Get rid of the big set
266     unload_master_texture_properties();
267     textures_loaded = TRUE;
268     game_fr_reparam(all_textures, -1, -1);
269 }
270 
free_textures(void)271 void free_textures(void) {
272 #ifndef SVGA_CUTSCENES
273     if (all_textures && (tmap_dynamic_mem == NULL))
274         free(tmap_dynamic_mem);
275 #endif
276     tmaps_setup = FALSE;
277 }
278 
bitmap_array_unload(int * num_bitmaps,grs_bitmap * arr[])279 errtype bitmap_array_unload(int *num_bitmaps, grs_bitmap *arr[]) {
280     int i;
281 
282     if (*num_bitmaps == 0)
283         return (ERR_NOEFFECT);
284 
285     // Spew(DSRC_SYSTEM_Memory, ("Freeing %d bitmaps...\n",*num_bitmaps));
286     for (i = 0; i < *num_bitmaps; i++) {
287         //      Spew(DSRC_SYSTEM_Memory, ("%d ",i));
288         free(arr[i]->bits);
289         free(arr[i]);
290     }
291     *num_bitmaps = 0;
292     return (OK);
293 }
294 
empty_bitmap(grs_bitmap * bmp)295 uchar empty_bitmap(grs_bitmap *bmp) {
296     uchar *cur = &bmp->bits[0], *targ = cur + (bmp->w * bmp->h);
297     while (cur < targ)
298         if (*cur++ != 0)
299             return FALSE;
300     return TRUE;
301 }
302 
Init_Lighting(void)303 errtype Init_Lighting(void) {
304     int i;
305     FILE *fp;
306 
307     fp = fopen_caseless("res/data/shadtabl.dat", "rb");
308     if (fp == NULL)
309         return (ERR_FOPEN);
310     fread(shading_table, 1, 256 * 16, fp);
311     fclose(fp);
312 
313     for (i = 0; i < 256 * 16; i += 256) {
314         shading_table[i] = 0xFF; // i love our shading table
315     }
316 
317     DEBUG("Set Light Table");
318     gr_set_light_tab(shading_table);
319 
320     // now read bw shading table
321     fp = fopen_caseless("res/data/bwtabl.dat", "rb");
322     if (fp == NULL)
323         return (ERR_FOPEN);
324     fread(bw_shading_table, 1, 256 * 16, fp);
325     fclose(fp);
326 
327     for (i = 0; i < 256 * 16; i += 256)
328         bw_shading_table[i] = 0; // i love our shading table
329 
330     fr_set_cluts(shading_table, bw_shading_table, bw_shading_table, bw_shading_table);
331 
332     return (OK);
333 }
334 
load_master_texture_properties(void)335 errtype load_master_texture_properties(void) {
336     int version, i;
337     char *cp;
338 
339     texture_properties = (TextureProp *)malloc(GAME_TEXTURES * sizeof(TextureProp));
340 
341     // Load Properties from disk
342     clear_texture_properties();
343 
344     DEBUG("Loading texture properties");
345 
346     FILE *f = fopen_caseless("res/data/textprop.dat", "rb");
347 
348     if (f == NULL) {
349         return (ERR_FOPEN);
350     }
351 
352     fseek(f, 0, SEEK_END);
353     int len = ftell(f);
354     rewind(f);
355 
356     cp = (char *)malloc((len + 1) * sizeof(char));
357     fread(cp, len, 1, f);
358     fclose(f);
359 
360     {
361         memmove(&version, cp, sizeof(version));
362         cp += sizeof(version);
363 
364         if (version == TEXTPROP_VERSION_NUMBER) {
365             // 363 seems magic. GAME_TEXTURES instead?
366             for (i = 0; i < 363; i++) {
367                 memmove(&texture_properties[i], cp, 11);
368                 cp += 11;
369             }
370         } else {
371             ERROR("Skipping loading textprops.dat, bad version!");
372         }
373     }
374 
375     /*res = GetResource('tprp',1000);
376     if (res)
377      {
378       FlipLong((long *) (*res));
379       version =  * (int *) (*res);
380       if (version == TEXTPROP_VERSION_NUMBER)
381        {
382         // copy out the structs, fixing the 11->12 byte size difference
383         for (i=0; i<363; i++)
384           texture_properties[i] = * (TextureProp *) (*res+4+(i*11));
385 
386         // fix shorts in texture_properties
387         for (i=0; i<GAME_TEXTURES; i++)
388          {
389           FlipShort(&texture_properties[i].resilience);
390           FlipShort(&texture_properties[i].distance_mod);
391          }
392        }
393           ReleaseResource(res);
394      }*/
395     // MLA- changed this to use resources
396     // if (DatapathFind(&DataDirPath, levname, path))
397     /*{
398        FILE* f = fopen("res/data/textprop.dat", "rb");
399        if (f != NULL)
400        {
401           fread(version, sizeof(short), 1, f);
402           if (version == TEXTPROP_VERSION_NUMBER)
403           {
404              fread(&texture_properties, 1, GAME_TEXTURES * 10, f);
405           }
406           else {
407              printf("Bad Texture Properties version number (%d).  Current = %d.\n",version,TEXTPROP_VERSION_NUMBER);
408           }
409  //         else
410  //            Warning(("Bad Texture Properties version number (%d).  Current =
411  %d.\n",version,TEXTPROP_VERSION_NUMBER)); fclose(f);
412        }
413        else {
414           printf("Cannot load textprops!\n");
415        }
416      }*/
417 
418     return (OK);
419 }
420 
unload_master_texture_properties(void)421 errtype unload_master_texture_properties(void) {
422     free(texture_properties);
423     texture_properties = NULL;
424     return (OK);
425 }
426 
clear_texture_properties(void)427 errtype clear_texture_properties(void) {
428     int i;
429 
430     // clear it all
431     LG_memset(texture_properties, 0, sizeof(TextureProp) * GAME_TEXTURES);
432 
433     // set the stuff that needs values besides zero
434     for (i = 0; i < GAME_TEXTURES; i++) {
435         texture_properties[i].family_texture = i;
436         texture_properties[i].target_texture = i;
437         texture_properties[i].resilience = 10;
438     }
439     return (OK);
440 }
441 
442     //#define TEXTURE_CRUNCH_HACK
443 
444 #ifdef TEXTURE_CRUNCH_HACK
445 
446 #define NUM_CONVERT 93
447 short convert_list[NUM_CONVERT][2] = {
448     {0, 144,},
449     {3, 115,},
450     {9, 8,},
451     {11, 158,},
452     {13, 7,},
453     {15, 14},
454     {16, 158,},
455     {45, 158,},
456     {46, 158,},
457     {47, 158,},
458     {48, 49,},
459     {50, 49,},
460     {51, 49,},
461     {59, 58,},
462     {61, 62,},
463     {67, 66,},
464     {73, 158,},
465     {86, 158,},
466     {87, 158,},
467     {92, 93,},
468     {94, 158,},
469     {98, 158,},
470     {99, 158,},
471     {100, 158,},
472     {105, 158,},
473     {106, 158,},
474     {107, 158,},
475     {109, 158,},
476     {123, 122,},
477     {124, 125,},
478     {128,158,},
479     {129,158,},
480     {133, 132,},
481     {150,158,},
482     {151,158,},
483     {152, 158,},
484     {153,158,},
485     {154, 158,},
486     {155,158,},
487     {156,158,},
488     {169,167,},
489     {170, 164,},
490     {173,160,},
491     {179,158,},
492     {180,158,},
493     {181,158,},
494     {184,158,},
495     {185,158,},
496     {187,158,},
497     {194,158,},
498     {197,158,},
499     {198,158,},
500     {199,158,},
501     {200,158,},
502     {201,158,},
503     {202,158,},
504     {203,158,},
505     {204,158,},
506     {207,158,},
507     {211,158,},
508     {212,205,},
509     {213,158,},
510     {239,158,},
511     {240,241,},
512     {245,244,},
513     {247,246,},
514     {250,249,},
515     {251,249,},
516     {254,249,},
517     {255,249,},
518     {260,259,},
519     {261,158,},
520     {269,266,},
521     {275,158,},
522     {276,158,},
523     {277,266,},
524     {279,266,},
525     {282,281,},
526     {292,158,},
527     {293,158,},
528     {295,158,},
529     {296,294,},
530     {297,294,},
531     {298,294,},
532     {299,294,},
533     {300,158,},
534     {301,157,},
535     {309,158,},
536     {310,158,},
537     {311,158,},
538     {318,158,},
539     {343,158,},
540     {351,350,}
541 };
542 
543 short tmap_convert[GAME_TEXTURES];
544 short tmap_crunch[GAME_TEXTURES];
545 
texture_crunch_init(void)546 errtype texture_crunch_init(void) {
547     int i, c;
548     for (i = 0; i < GAME_TEXTURES; i++)
549         tmap_convert[i] = i;
550     for (i = 0; i < NUM_CONVERT; i++)
551         tmap_convert[convert_list[i][0]] = convert_list[i][1];
552     c = 0;
553     for (i = 0; i < GAME_TEXTURES; i++) {
554         if (tmap_convert[i] == i)
555             tmap_crunch[i] = c++;
556         else
557             tmap_crunch[i] = -1;
558     }
559     return (OK);
560 }
561 
texture_crunch_go(void)562 errtype texture_crunch_go(void) {
563     int i;
564 
565     for (i = 0; i < NUM_LOADED_TEXTURES; i++) {
566         // Warning(("%d=%d->%d->%d\n",i,loved_textures[i],tmap_convert[loved_textures[i]],tmap_crunch[tmap_convert[loved_textures[i]]]));
567         loved_textures[i] = tmap_crunch[tmap_convert[loved_textures[i]]];
568     }
569     load_textures();
570 
571     return (OK);
572 }
573 #endif
574 
575     //#define TEXTURE_ANNIHILATION
576 
577 #ifdef TEXTURE_ANNIHILATION
578 #define NUM_DEMO_TEXTURES 32
579 #pragma disable_message(202)
580 uchar salvation_list[GAME_TEXTURES];
texture_annihilate_func(ushort keycode,uint32_t context,intptr_t data)581 uchar texture_annihilate_func(ushort keycode, uint32_t context, intptr_t data) {
582     int fn;
583     int i, c;
584     extern int texture_fnum;
585 
586     mprintf("texture_fnum = %d\n", texture_fnum);
587     if (texture_fnum == 0) {
588         // Warning(("HEY, TEXTURE_FNUM is %d!\n",texture_fnum));
589         return (TRUE);
590     }
591 
592     ResCloseFile(texture_fnum);
593 
594     fn = ResEditFile("texture.res", FALSE);
595 
596     for (i = 0; i < GAME_TEXTURES; i++)
597         salvation_list[i] = FALSE;
598 
599     // Determine which textures are fine and happy
600     for (i = 0; i < NUM_DEMO_TEXTURES; i++) {
601         salvation_list[loved_textures[i]] = TRUE;
602     }
603 
604     // Annhiliate all that do not conform... except for 16x16s which are in
605     // always since it's annoying to remove them!
606     for (i = 0; i < GAME_TEXTURES; i++) {
607         if (!salvation_list[i]) {
608             mprintf("destroying number %d, id = %x and %x\n", i, TEXTURE_64_ID + i, TEXTURE_128_ID + i);
609             if (!ResInUse(TEXTURE_64_ID + i))
610                 break;
611             else {
612                 ResKill(TEXTURE_64_ID + i);
613                 ResKill(TEXTURE_128_ID + i);
614             }
615         }
616     }
617 
618     ResPack(fn);
619 
620     ResCloseFile(fn);
621 
622     texture_fnum = ResOpenFile("texture.res");
623 
624     return (TRUE);
625 }
626 #pragma enable_message(202)
627 #endif
628