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