1 #if 1
2
3
4 #include "3dc.h"
5
6 #include <sys/stat.h>
7
8 #include "inline.h"
9
10 #ifdef RIFF_SYSTEM
11 #include "chnktexi.h"
12 #endif
13
14 #define UseLocalAssert 0
15 #include "ourasert.h"
16
17 #else
18
19 #include <stdio.h>
20 #include <sys/stat.h>
21
22 #include "system.h"
23 #include "equates.h"
24 #include "platform.h"
25 #include "shape.h"
26 #include "prototyp.h"
27 #include "inline.h"
28
29 #ifdef RIFF_SYSTEM
30 #include "chnktexi.h"
31 #endif
32
33
34 #endif
35
36
37 #include "awtexld.h"
38
39 #if 0 /* SBF - commented out */
40 #include "alt_tab.h"
41 #endif
42
43 /*
44 #define for experimental purposes
45 ONLY!!!
46 */
47
48 #define DefinedTextureType TextureTypePPM
49
50
51 /*
52
53 externs for commonly used global variables and arrays
54
55 */
56
57 extern SHAPEHEADER **mainshapelist;
58 extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
59 extern unsigned char *ScreenBuffer;
60 extern char projectsubdirectory[];
61 extern int ScanDrawMode;
62 extern int VideoModeType;
63
64 /*
65
66 Global Variables for PC Functions
67
68 */
69
70 TEXTURE *ImageBuffer; /* Memory Resident Image Data */
71
72 #ifdef MaxImageGroups
73 #if MaxImageGroups < 2 /* optimize if this multiple groups are not required */
74 #undef MaxImageGroups
75 #endif /* MaxImageGroups < 2 */
76 #endif /* MaxImageGroups */
77
78 #ifdef MaxImageGroups
79
80 #include "txioctrl.h"
81
82 /*
83 basically, I want there to be more than one image header array
84 so that I can load some images once only, then load shapes, call
85 InitializeTextures, DeallocateAllImages, etc. and only the images associated
86 with the shapes load are deallocated.
87 I might want to load shapes in two blocks, calling InitializeTextures
88 for each load.
89
90 There will need to be as many slots for ImageHeaderArrays as MaxImageGroups
91
92 I want this to be completely invisible to anyone except programmers on
93 PC projects that require this feature
94
95 Jake.
96 */
97
98 /* these three globals must behave the same */
99 int NumImages = 0; /* # current images */
100 IMAGEHEADER *ImageHeaderPtrs[MaxImageGroups*MaxImages]; /* Ptrs to Image Header Blocks */
101 IMAGEHEADER ImageHeaderArray[MaxImageGroups*MaxImages]; /* Array of Image Headers */
102
103 int NumImagesArray[MaxImageGroups]; /* must be static to ensure initialization to zero */
104 static int CurrentImageGroup = 0;
105 static IMAGEHEADER *NextFreeImageHeaderPtr[MaxImageGroups];
106
107 #else /* ! MaxImageGroups */
108
109 int NumImages = 0; /* # current images */
110 IMAGEHEADER *ImageHeaderPtrs[MaxImages]; /* Ptrs to Image Header Blocks */
111 IMAGEHEADER ImageHeaderArray[MaxImages]; /* Array of Image Headers */
112
113 static IMAGEHEADER *NextFreeImageHeaderPtr;
114
115 #endif /* ! MaxImageGroups */
116
117
118 /*
119
120 Initialise General Texture Data Structures and Variables
121
122 */
123
124
125 #if LoadingMapsShapesAndTexturesEtc
126
127
InitialiseImageHeaders(void)128 void InitialiseImageHeaders(void)
129
130 {
131 #ifdef MaxImageGroups
132
133 NumImages = CurrentImageGroup * MaxImages;
134 NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
135
136 #else
137
138 NumImages = 0;
139 NextFreeImageHeaderPtr = ImageHeaderArray;
140
141 #endif
142 }
143
144 #else
145
146
147 #define InitTexPrnt No
148
InitialiseTextures(void)149 int InitialiseTextures(void)
150
151 {
152
153 SHAPEHEADER **shlistptr;
154 SHAPEHEADER *shptr;
155 char **txfiles;
156 int TxIndex;
157 int LTxIndex;
158
159 /*
160
161 Free up any currently loaded images
162
163 The caller is responsible for any other structures which might refer
164 to the currently loaded images
165
166 */
167
168 #ifdef MaxImageGroups
169
170 DeallocateCurrentImages();
171
172 NumImages = CurrentImageGroup * MaxImages;
173 NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
174
175 #else
176
177 DeallocateAllImages();
178
179 /* Initialise Image Header Variables */
180
181 NumImages = 0;
182 NextFreeImageHeaderPtr = ImageHeaderArray;
183
184 #endif
185
186 /* Added 23/3/98 by DHM so that this can be called without loading any
187 shapes (to get textprint working in the menus):
188 */
189 if ( NULL == mainshapelist )
190 {
191 return Yes;
192 // early exit
193 }
194
195 /* Build the Texture List */
196
197 shlistptr = &mainshapelist[0];
198
199 while(*shlistptr) {
200
201 shptr = *shlistptr++;
202
203 /* If the shape has textures */
204
205 if(shptr->sh_localtextures) {
206
207 #if InitTexPrnt
208 textprint("This shape has textures\n");
209 #endif
210
211 txfiles = shptr->sh_localtextures;
212
213 LTxIndex = 0;
214
215 while(*txfiles) {
216
217 /* The RIFF Image loaders have changed to support not loading the same image twice - JH 17-2-96 */
218
219 char *src;
220 char *dst;
221 char fname[ImageNameSize];
222 char *txfilesptr;
223 #ifndef RIFF_SYSTEM
224 int i, j, NewImage;
225 char *iname;
226 IMAGEHEADER *ihptr;
227 IMAGEHEADER *new_ihptr;
228 void* im;
229 #endif
230
231 txfilesptr = *txfiles++;
232
233 /*
234
235 "txfilesptr" is in the form "textures\<fname>". We need to
236 prefix that text with the name of the current textures path.
237
238 Soon this path may be varied but for now it is just the name of
239 the current project subdirectory.
240
241 */
242
243 src = projectsubdirectory;
244 dst = fname;
245
246 while(*src)
247 *dst++ = *src++;
248
249 src = txfilesptr;
250
251 while(*src)
252 *dst++ = *src++;
253
254 *dst = 0;
255
256
257 #if InitTexPrnt
258 textprint(" A Texture\n");
259 #endif
260
261
262 #ifdef RIFF_SYSTEM
263
264 /* This function calls GetExistingImageHeader to figure out if the image is already loaded */
265 TxIndex = CL_LoadImageOnce(fname,(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RELATIVEPATH|LIO_RESTORABLE);
266 GLOBALASSERT(GEI_NOTLOADED != TxIndex);
267
268 #else
269
270 /* If there are already images, try and find this one */
271
272 NewImage = Yes;
273
274 #ifdef MaxImageGroups
275
276 TxIndex = CurrentImageGroup * MaxImages; /* Assume image 0 */
277
278 if(NumImagesArray[CurrentImageGroup]) {
279
280 for(i=NumImagesArray[CurrentImageGroup]; i!=0 && NewImage!=No; i--) {
281
282 #else
283
284 TxIndex = 0; /* Assume image 0 */
285
286 if(NumImages) {
287
288 for(i=NumImages; i!=0 && NewImage!=No; i--) {
289
290 #endif
291
292 ihptr = ImageHeaderPtrs[TxIndex];
293
294 iname = &ihptr->ImageName[0];
295
296 j = CompareFilenameCH(txfilesptr, iname);
297
298 if(j) NewImage = No;
299
300 else TxIndex++;
301
302 }
303
304 }
305
306
307 /* If this is a new image, add it */
308
309 if(NewImage) {
310
311 #if InitTexPrnt
312 textprint("New Image\n");
313 WaitForReturn();
314 #endif
315
316 /* Get an Image Header */
317
318 new_ihptr = GetImageHeader();
319
320 if(new_ihptr) {
321
322 if (ScanDrawMode == ScanDrawDirectDraw)
323 im = (void*) LoadImageCH(&fname[0], new_ihptr);
324 else
325 im = LoadImageIntoD3DImmediateSurface
326 (&fname[0], new_ihptr, DefinedTextureType);
327
328 if(im) {
329
330 #if InitTexPrnt
331 textprint("Load OK, NumImages = %d\n", NumImages);
332 WaitForReturn();
333 #endif
334
335 }
336
337 }
338
339 }
340
341
342 /* test */
343
344 #if InitTexPrnt
345 else textprint("Image Already Exists\n");
346 #endif
347
348 #endif
349
350 /*
351
352 The local index for this image in this shape is
353 "LTxIndex".
354
355 The global index for the image is "TxIndex".
356
357 We must go through the shape's items and change all the
358 local references to global.
359
360 */
361
362 #if InitTexPrnt
363 textprint("\nLocal to Global for Shape\n");
364 #endif
365
366 MakeShapeTexturesGlobal(shptr, TxIndex, LTxIndex);
367
368 LTxIndex++; /* Next Local Texture */
369
370 }
371
372 /* Is this shape a sprite that requires resizing? */
373
374 if((shptr->shapeflags & ShapeFlag_Sprite) &&
375 (shptr->shapeflags & ShapeFlag_SpriteResizing)) {
376
377 SpriteResizing(shptr);
378
379 }
380
381 }
382
383 }
384
385 #if InitTexPrnt
386 textprint("\nFinished PP for textures\n");
387
388 WaitForReturn();
389
390 #endif
391
392 return Yes;
393 }
394
395
396 #endif
397
398
399 /*
400
401 This function accepts a shape header, a global texture index and a local
402 index. It searches through all the items that use textures and converts all
403 local references to a texture to global references.
404
405 The index to a texture that refers to the IMAGEHEADER pointer array is in
406 the low word of the colour int.
407
408 Bit #15 is set if this index refers to a local texture.
409
410 Here is an example of a textured item:
411
412
413 int CUBE_item3[]={
414
415 I_2dTexturedPolygon,3*vsize,0,
416
417 (3<<TxDefn) + TxLocal + 0,
418
419 7*vsize,5*vsize,1*vsize,3*vsize,
420 Term
421
422 };
423
424
425 To test for a local texture use:
426
427 if(ColourInt & TxLocal)
428
429
430
431 NOTE
432
433 The procedure is NOT reversible!
434
435 If one wishes to reconstruct the table, all the shapes and textures must be
436 reloaded and the initialisation function recalled.
437
438 Actually a function could be written that relates global filenames back to
439 local filenames, so in a sense that is not true. This function will only be
440 written if it is needed.
441
442 */
443
444 void MakeShapeTexturesGlobal(SHAPEHEADER *shptr, int TxIndex, int LTxIndex)
445
446 {
447
448 int **ShapeItemArrayPtr;
449 POLYHEADER *ShapeItemPtr;
450
451 #if SupportBSP
452 SHAPEDATA_BSP_BLOCK *ShapeBSPPtr;
453 int num_bsp_blocks;
454 int j, k;
455 #endif
456
457 int i, txi;
458
459
460 /* Are the items in a pointer array? */
461
462 if(shptr->items) {
463
464 #if InitTexPrnt
465 textprint("Item Array\n");
466 #endif
467
468 ShapeItemArrayPtr = shptr->items;
469
470 for(i = shptr->numitems; i!=0; i--) {
471
472 ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++;
473
474 #if SupportZBuffering
475
476 if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
477 || ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon
478 || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
479 || ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon
480 || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
481 || ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon
482 || ShapeItemPtr->PolyItemType == I_ScaledSprite
483 || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon
484 || ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) {
485 #else
486 if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
487 || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
488 || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
489 || ShapeItemPtr->PolyItemType == I_ScaledSprite
490 || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon){
491 #endif /* SupportZBuffering */
492
493 if(ShapeItemPtr->PolyFlags & iflag_txanim) {
494
495 MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr,
496 LTxIndex, TxIndex);
497
498 }
499
500 if(ShapeItemPtr->PolyColour & TxLocal) {
501
502 txi = ShapeItemPtr->PolyColour;
503 txi &= ~TxLocal; /* Clear Flag */
504 txi &= ClrTxDefn; /* Clear UV array index */
505
506 /* Is this the local index? */
507
508 if(txi == LTxIndex) {
509
510 /* Clear low word, OR in global index */
511
512 ShapeItemPtr->PolyColour &= ClrTxIndex;
513 ShapeItemPtr->PolyColour |= TxIndex;
514
515 }
516
517 }
518
519 }
520
521 }
522
523 }
524
525 #if SupportBSP
526
527 /* Or are they in a BSP block array? */
528
529 else if(shptr->sh_bsp_blocks) {
530
531 #if InitTexPrnt
532 textprint("BSP Block Array\n");
533 #endif
534
535 #if 0
536 /* Find the BSP Instruction */
537 ShInstrPtr = shptr->sh_instruction;
538 num_bsp_blocks = 0;
539 while(ShInstrPtr->sh_instr != I_ShapeEnd) {
540 if(ShInstrPtr->sh_instr == I_ShapeBSPTree) {
541 num_bsp_blocks = ShInstrPtr->sh_numitems;
542 }
543 ShInstrPtr++;
544 }
545 #endif
546
547 num_bsp_blocks = FindNumBSPNodes(shptr);
548
549
550 #if InitTexPrnt
551 textprint("Number of BSP blocks = %d\n", num_bsp_blocks);
552 #endif
553
554 if(num_bsp_blocks) {
555
556 ShapeBSPPtr = shptr->sh_bsp_blocks;
557
558 for(k=num_bsp_blocks; k!=0; k--) {
559
560 ShapeItemArrayPtr = ShapeBSPPtr->bsp_block_data;
561
562 for(j=ShapeBSPPtr->bsp_numitems; j!=0; j--) {
563
564 ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++;
565
566 #if InitTexPrnt
567 textprint("shape item\n");
568 #endif
569
570 if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
571 || ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon
572 || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
573 || ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon
574 || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
575 || ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon
576 || ShapeItemPtr->PolyItemType == I_ScaledSprite
577 || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon
578 || ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) {
579
580 if(ShapeItemPtr->PolyFlags & iflag_txanim) {
581
582 MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr,
583 LTxIndex, TxIndex);
584
585 }
586
587 #if InitTexPrnt
588 textprint(" - textured\n");
589 #endif
590
591 if(ShapeItemPtr->PolyColour & TxLocal) {
592
593 #if InitTexPrnt
594 textprint(" - local index\n");
595 #endif
596
597 txi = ShapeItemPtr->PolyColour;
598 txi &= ~(TxLocal); /* Clear Flag */
599 txi &= ClrTxDefn; /* Clear Defn */
600
601 #if InitTexPrnt
602 textprint(" - is %d\n", txi);
603 textprint(" - LTxIndex is %d\n", LTxIndex);
604 #endif
605
606 /* Is this the local index? */
607
608 if(txi == LTxIndex) {
609
610 /* Clear low word, OR in global index */
611
612 ShapeItemPtr->PolyColour &= ClrTxIndex;
613 ShapeItemPtr->PolyColour |= TxIndex;
614
615 #if InitTexPrnt
616 textprint("Local %d, Global %d\n", LTxIndex, TxIndex);
617 #endif
618
619 }
620
621 }
622
623 }
624
625 }
626
627 ShapeBSPPtr++;
628
629 }
630
631 }
632
633 }
634
635 #endif /* SupportBSP */
636
637 /* Otherwise the shape has no item data */
638
639
640 }
641
642
643 /*
644
645 The animated texture frames each have a local image index in their frame
646 header structure. Convert these to global texture list indices in the same
647 way that the item function does.
648
649 */
650
651 void MakeTxAnimFrameTexturesGlobal(SHAPEHEADER *sptr,
652 POLYHEADER *pheader,
653 int LTxIndex, int TxIndex)
654
655 {
656
657 TXANIMHEADER **txah_ptr;
658 TXANIMHEADER *txah;
659 TXANIMFRAME *txaf;
660 int **shape_textures;
661 int *txf_imageptr;
662 int texture_defn_index;
663 int i, txi, image;
664
665
666 #if 0
667 textprint("LTxIndex = %d, TxIndex = %d\n", LTxIndex, TxIndex);
668 WaitForReturn();
669 #endif
670
671
672 /* Get the animation sequence header */
673
674 shape_textures = sptr->sh_textures;
675 texture_defn_index = (pheader->PolyColour >> TxDefn);
676 txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index];
677
678
679 /* The first array element is the sequence shadow, which we skip here */
680
681 txah_ptr++;
682
683
684 /* Process the animation sequences */
685
686 while(*txah_ptr) {
687
688 /* Get the animation header */
689
690 txah = *txah_ptr++;
691
692 /* Process the animation frames */
693
694 if(txah && txah->txa_numframes) {
695
696 txaf = txah->txa_framedata;
697
698 for(i = txah->txa_numframes; i!=0; i--) {
699
700 /* Multi-View Sprite? */
701
702 if(sptr->shapeflags & ShapeFlag_MultiViewSprite) {
703
704 txf_imageptr = (int *) txaf->txf_image;
705
706 for(image = txah->txa_num_mvs_images; image!=0; image--) {
707
708 if(*txf_imageptr & TxLocal) {
709
710 txi = *txf_imageptr;
711 txi &= ~TxLocal; /* Clear Flag */
712
713 if(txi == LTxIndex) {
714
715 *txf_imageptr = TxIndex;
716
717 }
718
719 }
720
721 txf_imageptr++;
722
723 }
724
725 }
726
727 else {
728
729 if(txaf->txf_image & TxLocal) {
730
731 txi = txaf->txf_image;
732 txi &= ~TxLocal; /* Clear Flag */
733
734 if(txi == LTxIndex) {
735
736 txaf->txf_image = TxIndex;
737
738 }
739
740 }
741
742 }
743
744 txaf++;
745
746 }
747
748 }
749
750 }
751
752 }
753
754
755
756 /*
757
758 Sprite Resizing
759
760 or
761
762 An Optimisation For Sprite Images
763
764 This shape is a sprite which has requested the UV rescaling optimisation.
765 The UV array is resized to fit the sprite image bounding rectangle, and
766 after the UV array, in the space provided (don't forget that!), is a new
767 shape local space XY array of points which overwrite the standard values
768 when the shape is displayed.
769
770 */
771
772 #define sr_print No
773
774 void SpriteResizing(SHAPEHEADER *sptr)
775
776 {
777
778 TXANIMHEADER **txah_ptr;
779 TXANIMHEADER *txah;
780 TXANIMFRAME *txaf;
781 int **shape_textures;
782 IMAGEHEADER *ihdr;
783 IMAGEEXTENTS e;
784 IMAGEEXTENTS e_curr;
785 IMAGEPOLYEXTENTS e_poly;
786 int *uvptr;
787 int texture_defn_index;
788 int **item_array_ptr;
789 int *item_ptr;
790 POLYHEADER *pheader;
791 int i, f;
792 int polypts[4 * vsize];
793 int *iptr;
794 int *iptr2;
795 int *mypolystart;
796 int *ShapePoints = *(sptr->points);
797 VECTOR2D cen_poly;
798 VECTOR2D size_poly;
799 VECTOR2D cen_uv_curr;
800 VECTOR2D size_uv_curr;
801 VECTOR2D cen_uv;
802 VECTOR2D size_uv;
803 VECTOR2D tv;
804 int *txf_imageptr;
805 int **txf_uvarrayptr;
806 int *txf_uvarray;
807 int image;
808 int num_images;
809
810
811 #if sr_print
812 textprint("\nSprite Resize Shape\n\n");
813 #endif
814
815
816 /* Get the animation sequence header */
817
818 shape_textures = sptr->sh_textures;
819
820 item_array_ptr = sptr->items; /* Assume item array */
821 item_ptr = item_array_ptr[0]; /* Assume only one polygon */
822 pheader = (POLYHEADER *) item_ptr;
823
824
825 /* Get the polygon points, and at the same time the extents, assuming an XY plane polygon */
826
827 e_poly.x_low = bigint;
828 e_poly.y_low = bigint;
829
830 e_poly.x_high = smallint;
831 e_poly.y_high = smallint;
832
833 iptr = polypts;
834 mypolystart = &pheader->Poly1stPt;
835
836 for(i = 4; i!=0; i--) {
837
838 iptr[ix] = ((VECTORCH*)ShapePoints)[*mypolystart].vx;
839 iptr[iy] = ((VECTORCH*)ShapePoints)[*mypolystart].vy;
840 iptr[iz] = ((VECTORCH*)ShapePoints)[*mypolystart].vz;
841
842 if(iptr[ix] < e_poly.x_low) e_poly.x_low = iptr[ix];
843 if(iptr[iy] < e_poly.y_low) e_poly.y_low = iptr[iy];
844 if(iptr[ix] > e_poly.x_high) e_poly.x_high = iptr[ix];
845 if(iptr[iy] > e_poly.y_high) e_poly.y_high = iptr[iy];
846
847 iptr += vsize;
848 mypolystart++;
849
850 }
851
852
853 texture_defn_index = (pheader->PolyColour >> TxDefn);
854 txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index];
855
856
857 /* The first array element is the sequence shadow, which we skip here */
858
859 txah_ptr++;
860
861
862 /* Process the animation sequences */
863
864 while(*txah_ptr) {
865
866 /* Get the animation header */
867
868 txah = *txah_ptr++;
869
870 /* Process the animation frames */
871
872 if(txah && txah->txa_numframes) {
873
874 txaf = txah->txa_framedata;
875
876 for(f = txah->txa_numframes; f!=0; f--) {
877
878
879 /* Multi-View Sprite? */
880
881 if(sptr->shapeflags & ShapeFlag_MultiViewSprite) {
882
883 txf_imageptr = (int *) txaf->txf_image;
884 num_images = txah->txa_num_mvs_images;
885
886 txf_uvarrayptr = (int **) txaf->txf_uvdata;
887
888 }
889
890 /* A standard "Single View" Sprite has just one image */
891
892 else {
893
894 txf_imageptr = &txaf->txf_image;
895 num_images = 1;
896
897 txf_uvarrayptr = &txaf->txf_uvdata;
898
899 }
900
901
902 for(image = 0; image < num_images; image++) {
903
904
905 #if sr_print
906 textprint("image %d of %d \n", (image + 1), num_images);
907 #endif
908
909
910 /* Get the image */
911
912 ihdr = ImageHeaderPtrs[txf_imageptr[image]];
913
914 /* Get the uv array ptr */
915
916 txf_uvarray = txf_uvarrayptr[image];
917
918 /* Find the extents of the image, assuming transparency */
919
920 #if 0
921 FindImageExtents(ihdr, txaf->txf_numuvs, txaf->txf_uvdata, &e, &e_curr);
922 #else
923 FindImageExtents(ihdr, txaf->txf_numuvs, txf_uvarray, &e, &e_curr);
924 #endif
925
926 /* Convert the image extents to fixed point */
927
928 #if sr_print
929 textprint("extents = %d, %d\n", e.u_low, e.v_low);
930 textprint(" %d, %d\n", e.u_high, e.v_high);
931 WaitForReturn();
932 #endif
933
934 e.u_low <<= 16;
935 e.v_low <<= 16;
936 e.u_high <<= 16;
937 e.v_high <<= 16;
938
939 /*
940
941 We now have all the information needed to create a NEW UV array and a NEW
942 polygon points XY array.
943
944 */
945
946 /* Centre of the polygon */
947
948 cen_poly.vx = (e_poly.x_low + e_poly.x_high) / 2;
949 cen_poly.vy = (e_poly.y_low + e_poly.y_high) / 2;
950
951 /* Size of the polygon */
952
953 size_poly.vx = e_poly.x_high - e_poly.x_low;
954 size_poly.vy = e_poly.y_high - e_poly.y_low;
955
956
957 /* Centre of the current cookie */
958
959 cen_uv_curr.vx = (e_curr.u_low + e_curr.u_high) / 2;
960 cen_uv_curr.vy = (e_curr.v_low + e_curr.v_high) / 2;
961
962 /* Size of the current cookie */
963
964 size_uv_curr.vx = e_curr.u_high - e_curr.u_low;
965 size_uv_curr.vy = e_curr.v_high - e_curr.v_low;
966
967
968 /* Centre of the new cookie */
969
970 cen_uv.vx = (e.u_low + e.u_high) / 2;
971 cen_uv.vy = (e.v_low + e.v_high) / 2;
972
973 /* Size of the new cookie */
974
975 size_uv.vx = e.u_high - e.u_low;
976 size_uv.vy = e.v_high - e.v_low;
977
978
979 /* Write out the new UV data */
980
981 #if 0
982 uvptr = txaf->txf_uvdata;
983 #else
984 uvptr = txf_uvarray;
985 #endif
986
987
988 /*
989
990 Convert the duplicate UV array to this new scale
991 ASSUME that the format is "TL, BL, BR, TR"
992
993 */
994
995 uvptr[0] = e.u_low;
996 uvptr[1] = e.v_low;
997
998 uvptr[2] = e.u_low;
999 uvptr[3] = e.v_high;
1000
1001 uvptr[4] = e.u_high;
1002 uvptr[5] = e.v_high;
1003
1004 uvptr[6] = e.u_high;
1005 uvptr[7] = e.v_low;
1006
1007
1008 /*
1009
1010 Create the new polygon XY array
1011
1012 */
1013
1014 uvptr += (txaf->txf_numuvs * 2); /* Advance the pointer past the UV array */
1015
1016
1017 /* Copy the polygon points (XY only) to the UV array space */
1018
1019 iptr = polypts;
1020 iptr2 = uvptr;
1021
1022 for(i = 4; i!=0; i--) {
1023
1024 iptr2[0] = iptr[ix];
1025 iptr2[1] = iptr[iy];
1026
1027 iptr += vsize;
1028 iptr2 += 2;
1029
1030 }
1031
1032
1033 /* Scale the polygon points */
1034
1035 iptr = uvptr;
1036
1037 for(i = 4; i!=0; i--) {
1038
1039 iptr[0] = WideMulNarrowDiv(iptr[0], size_uv.vx, size_uv_curr.vx);
1040 iptr[1] = WideMulNarrowDiv(iptr[1], size_uv.vy, size_uv_curr.vy);
1041
1042 iptr += 2;
1043
1044 }
1045
1046
1047 /* The translation vector in UV space */
1048
1049 tv.vx = cen_uv.vx - cen_uv_curr.vx;
1050 tv.vy = cen_uv.vy - cen_uv_curr.vy;
1051
1052
1053 /* And now in world space */
1054
1055 tv.vx = WideMulNarrowDiv(tv.vx, size_poly.vx, size_uv_curr.vx);
1056 tv.vy = WideMulNarrowDiv(tv.vy, size_poly.vy, size_uv_curr.vy);
1057
1058
1059 /* Translate the polygon points */
1060
1061 iptr = uvptr;
1062
1063 for(i = 4; i!=0; i--) {
1064
1065 iptr[0] += tv.vx;
1066 iptr[1] += tv.vy;
1067
1068 iptr += 2;
1069
1070 }
1071
1072
1073 #if sr_print
1074 textprint(" (image done)\n");
1075 #endif
1076
1077
1078 }
1079
1080
1081 #if sr_print
1082 textprint("\n");
1083 #endif
1084
1085
1086 /* Next Texture Animation Frame */
1087
1088 txaf++;
1089
1090 }
1091
1092 }
1093
1094 }
1095
1096
1097 #if sr_print
1098 textprint("\nResize done\n\n");
1099 #endif
1100
1101 }
1102
1103
1104 /*
1105
1106 This function is for animated sprites, although it has been given an interface that would
1107 allow anyone to call it for their own purposes. It assumes that colour 0 is transparent and
1108 then calculates the actual maximum extents of the image.
1109
1110 NOTE:
1111
1112 The image scanned is that given by the CURRENT UV ARRAY and may therefore be smaller than
1113 the actual image. This allows for animation sequences with frames on the same image.
1114
1115 */
1116
1117 void FindImageExtents(IMAGEHEADER *ihdr, int numuvs, int *uvdata, IMAGEEXTENTS *e, IMAGEEXTENTS *e_curr)
1118
1119 {
1120
1121 int i;
1122 int *uvptr;
1123 int u, v;
1124 int startu, endu;
1125 int startv, endv;
1126
1127
1128 /* Find the current UV extents */
1129
1130 e_curr->u_low = bigint;
1131 e_curr->v_low = bigint;
1132
1133 e_curr->u_high = smallint;
1134 e_curr->v_high = smallint;
1135
1136 uvptr = uvdata;
1137
1138 for(i = numuvs; i!=0; i--) {
1139
1140 if(uvptr[0] < e_curr->u_low) e_curr->u_low = uvptr[0];
1141 if(uvptr[1] < e_curr->v_low) e_curr->v_low = uvptr[1];
1142
1143 if(uvptr[0] > e_curr->u_high) e_curr->u_high = uvptr[0];
1144 if(uvptr[1] > e_curr->v_high) e_curr->v_high = uvptr[1];
1145
1146 uvptr += 2;
1147
1148 }
1149
1150
1151 /* Look for the actual UV extents, assuming that colour 0 is transparent */
1152
1153 switch(VideoModeType) {
1154
1155 case VideoModeType_8:
1156
1157 {
1158
1159 TEXTURE *tptr = ihdr->ImagePtr;
1160 TEXTURE texel;
1161
1162
1163 /* Search for u_low and v_low */
1164
1165 e->u_low = bigint;
1166 e->v_low = bigint;
1167
1168 startv = e_curr->v_low >> 16;
1169 endv = e_curr->v_high >> 16;
1170 startu = e_curr->u_low >> 16;
1171 endu = e_curr->u_high >> 16;
1172
1173 for(v = startv; v <= endv; v++) {
1174
1175 for(u = startu; u <= endu; u++) {
1176
1177 texel = tptr[(v * ihdr->ImageWidth) + u];
1178
1179 if(texel) {
1180
1181 if(u < e->u_low) e->u_low = u;
1182 if(v < e->v_low) e->v_low = v;
1183
1184 }
1185
1186 }
1187
1188 }
1189
1190 if(e->u_low == bigint) e->u_low = e_curr->u_low;
1191 if(e->v_low == bigint) e->v_low = e_curr->v_low;
1192
1193
1194 /* Search for u_high and v_high */
1195
1196 e->u_high = smallint;
1197 e->v_high = smallint;
1198
1199 for(v = endv; v >= startv; v--) {
1200
1201 for(u = endu; u >= startu; u--) {
1202
1203 texel = tptr[(v * ihdr->ImageWidth) + u];
1204
1205 if(texel) {
1206
1207 if(u > e->u_high) e->u_high = u;
1208 if(v > e->v_high) e->v_high = v;
1209
1210 }
1211
1212 }
1213
1214 }
1215
1216 if(e->u_high == smallint) e->u_high = e_curr->u_high;
1217 if(e->v_high == smallint) e->v_high = e_curr->v_high;
1218
1219 }
1220
1221 break;
1222
1223 case VideoModeType_15:
1224 break;
1225
1226 case VideoModeType_24:
1227 break;
1228
1229 case VideoModeType_8T:
1230 break;
1231
1232 }
1233
1234 }
1235
1236
1237
1238 /*
1239
1240 Return a pointer to the next image header
1241
1242 */
1243
1244
1245 IMAGEHEADER* GetImageHeader(void)
1246 {
1247
1248 IMAGEHEADER *iheader;
1249
1250 #ifdef MaxImageGroups
1251
1252 /* NumImages always points to the correct point in the array */
1253 do
1254 {
1255 iheader = NextFreeImageHeaderPtr[CurrentImageGroup]++;
1256 }
1257 while (IsImageInUse(CurrentImageGroup,NumImagesArray[CurrentImageGroup]++) ? ++NumImages : 0);
1258
1259 GLOBALASSERT(NumImagesArray[CurrentImageGroup] < MaxImages);
1260
1261 #else
1262
1263 iheader = NextFreeImageHeaderPtr++;
1264 GLOBALASSERT(NumImages < MaxImages);
1265
1266 #endif
1267
1268 /* ensure flags are zero */
1269 memset(iheader,0,sizeof(IMAGEHEADER));
1270
1271 ImageHeaderPtrs[NumImages] = iheader;
1272 NumImages++;
1273
1274 return iheader;
1275
1276 }
1277
1278
1279 /*
1280
1281 Return the address of a texture image in memory, else null
1282
1283 */
1284
1285 #if 0
1286 void* GetTexture(int texindex)
1287
1288 {
1289
1290 /* Ahem... */
1291
1292 return No;
1293
1294 }
1295 #endif
1296
1297 /*
1298
1299 Allocate memory for a Texture Image
1300
1301 */
1302
1303 #if 0
1304 TEXTURE* GetTextureMemory(int txsize)
1305
1306 {
1307
1308 /* Err... */
1309 return No;
1310
1311 }
1312 #endif
1313
1314 /*
1315
1316 Deallocate memory for a Texture Image
1317
1318 */
1319
1320 #if 0
1321 void ReturnTextureMemory(TEXTURE *txptr)
1322
1323 {
1324
1325 }
1326 #endif
1327
1328 static void DeallocateImageHeader(IMAGEHEADER * ihptr)
1329 {
1330 if (ihptr->hBackup)
1331 {
1332 if (ihptr->DDSurface)
1333 {
1334 GLOBALASSERT(!ihptr->D3DTexture);
1335 ATRemoveSurface(ihptr->DDSurface);
1336 }
1337 else if (ihptr->D3DTexture)
1338 {
1339 GLOBALASSERT(!ihptr->DDSurface);
1340 ATRemoveTexture(ihptr->D3DTexture);
1341 }
1342
1343 AwDestroyBackupTexture(ihptr->hBackup);
1344 ihptr->hBackup = 0;
1345 }
1346
1347 if (ihptr->ImagePtr)
1348 {
1349 DeallocateMem(ihptr->ImagePtr);
1350 ihptr->ImagePtr = 0;
1351 }
1352
1353 if (ihptr->DDSurface)
1354 {
1355 ReleaseDDSurface(ihptr->DDSurface);
1356 ihptr->DDSurface = (void*) 0;
1357 }
1358
1359 if (ihptr->D3DTexture)
1360 {
1361 ReleaseD3DTexture(ihptr->D3DTexture);
1362 ihptr->D3DTexture = (void*) 0;
1363 ihptr->D3DHandle = /* (void*) */ 0;
1364 }
1365 }
1366
1367 static void MinimizeImageHeader(IMAGEHEADER * ihptr)
1368 {
1369 if (ihptr->DDSurface)
1370 {
1371 ReleaseDDSurface(ihptr->DDSurface);
1372 ihptr->DDSurface = (void*) 0;
1373 }
1374
1375 if (ihptr->D3DTexture)
1376 {
1377 ReleaseD3DTexture(ihptr->D3DTexture);
1378 ihptr->D3DTexture = (void*) 0;
1379 ihptr->D3DHandle = /* (void*) */ 0;
1380 }
1381 }
1382
1383 static void RestoreImageHeader(IMAGEHEADER * ihptr)
1384 {
1385 if (ScanDrawDirectDraw != ScanDrawMode)
1386 ReloadImageIntoD3DImmediateSurface(ihptr);
1387 }
1388
1389 #ifdef MaxImageGroups
1390
1391 void SetCurrentImageGroup(unsigned int group)
1392 {
1393 GLOBALASSERT(group < MaxImageGroups);
1394 CurrentImageGroup = group;
1395 NumImages = group*MaxImages + NumImagesArray[group];
1396 }
1397
1398 int DeallocateCurrentImages(void)
1399 {
1400 int i;
1401 IMAGEHEADER *ihptr;
1402
1403 if (NumImagesArray[CurrentImageGroup])
1404 {
1405 ihptr = &ImageHeaderArray[CurrentImageGroup*MaxImages];
1406 for (i = 0; i < NumImagesArray[CurrentImageGroup]; ++i)
1407 {
1408 if (CanDeleteImage(CurrentImageGroup,i))
1409 DeallocateImageHeader(ihptr);
1410 ++ihptr;
1411 }
1412 NumImagesArray[CurrentImageGroup] = 0;
1413 NumImages = CurrentImageGroup * MaxImages;
1414 NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
1415 ImageGroupFreed(CurrentImageGroup);
1416 }
1417
1418 return Yes; /* ok for the moment */
1419 }
1420
1421 void NowDeleteImage(int img_group, int img_num_offset)
1422 {
1423 DeallocateImageHeader(&ImageHeaderArray[img_group*MaxImages+img_num_offset]);
1424 }
1425
1426 int DeallocateAllImages(void)
1427 {
1428 int i, j;
1429 IMAGEHEADER *ihptr;
1430
1431 for (j=0; j<MaxImageGroups; ++j)
1432 {
1433 if (NumImagesArray[j])
1434 {
1435 ihptr = &ImageHeaderArray[j*MaxImages];
1436 for (i = 0; i<NumImagesArray[j]; ++i)
1437 {
1438 if (CanDeleteImage(j,i))
1439 DeallocateImageHeader(ihptr);
1440 ++ihptr;
1441 }
1442 NumImagesArray[j] = 0;
1443 }
1444 ImageGroupFreed(j);
1445 }
1446 NumImages = CurrentImageGroup * MaxImages;
1447 NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
1448
1449 return Yes; /* ok for the moment */
1450 }
1451
1452 static void MinimizeImageCallback(int i, void * gP)
1453 {
1454 int g = *(int *)gP;
1455 MinimizeImageHeader(ImageHeaderPtrs[g*MaxImages+i]);
1456 }
1457
1458 int MinimizeAllImages(void)
1459 {
1460 int i, j;
1461 IMAGEHEADER *ihptr;
1462
1463 for (j=0; j<MaxImageGroups; ++j)
1464 {
1465 if (NumImagesArray[j])
1466 {
1467 ihptr = &ImageHeaderArray[j*MaxImages];
1468 for (i = 0; i<NumImagesArray[j]; ++i)
1469 {
1470 MinimizeImageHeader(ihptr);
1471 ++ihptr;
1472 }
1473 }
1474 EnumLeftoverImages(j,NumImagesArray[j],MinimizeImageCallback,&j);
1475 }
1476
1477 return Yes; /* ok for the moment */
1478 }
1479
1480 static void RestoreImageCallback(int i, void * gP)
1481 {
1482 int g = *(int *)gP;
1483 RestoreImageHeader(ImageHeaderPtrs[g*MaxImages+i]);
1484 }
1485
1486 int RestoreAllImages(void)
1487 {
1488 int i, j;
1489 IMAGEHEADER *ihptr;
1490
1491 for (j=0; j<MaxImageGroups; ++j)
1492 {
1493 if (NumImagesArray[j])
1494 {
1495 ihptr = &ImageHeaderArray[j*MaxImages];
1496 for (i = 0; i<NumImagesArray[j]; ++i)
1497 {
1498 RestoreImageHeader(ihptr);
1499 ++ihptr;
1500 }
1501 }
1502 EnumLeftoverImages(j,NumImagesArray[j],RestoreImageCallback,&j);
1503 }
1504
1505 return Yes; /* ok for the moment */
1506 }
1507
1508 #if debug
1509
1510 struct ImageGroupDebugInfo
1511 {
1512 int num_texels;
1513 int num_images;
1514 int num_shared;
1515 int num_leftover;
1516 };
1517
1518 static struct ImageGroupDebugInfo db_gp_info[MaxImageGroups];
1519
1520 static void DbShareImgCallback(int imgnum, void * user)
1521 {
1522 int g = *(int *)user;
1523
1524 ++db_gp_info[g].num_shared;
1525 }
1526
1527 static void DbLeftoverImgCallback(int i, void * user)
1528 {
1529 int g = *(int *)user;
1530
1531 ++db_gp_info[g].num_leftover;
1532
1533 db_gp_info[g].num_texels += ImageHeaderPtrs[g*MaxImages+i]->ImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight;
1534 }
1535
1536 void ImageGroupsDebugPrintInit(void)
1537 {
1538 int g;
1539 for (g=0; g<MaxImageGroups; g++)
1540 {
1541 int i;
1542
1543 db_gp_info[g].num_texels = 0;
1544 db_gp_info[g].num_images = NumImagesArray[g];
1545 db_gp_info[g].num_shared = 0;
1546 db_gp_info[g].num_leftover = 0;
1547
1548 EnumSharedImages(g,NumImagesArray[g],DbShareImgCallback,&g);
1549 EnumLeftoverImages(g,NumImagesArray[g],DbLeftoverImgCallback,&g);
1550
1551 for (i=0; i<NumImagesArray[g]; ++i)
1552 {
1553 db_gp_info[g].num_texels += ImageHeaderPtrs[g*MaxImages+i]->ImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight;
1554 }
1555 }
1556 }
1557
1558 void ImageGroupsDebugPrint(void)
1559 {
1560 int g;
1561 textprint("IMAGE GROUP DEBUG INFO\nGP N_IMG N_SHR N_LFT N_TEXELS\n");
1562 for (g=0; g<MaxImageGroups; ++g)
1563 {
1564 textprint("%2d %5d %5d %5d %8d\n",g,db_gp_info[g].num_images,db_gp_info[g].num_shared,db_gp_info[g].num_leftover,db_gp_info[g].num_texels);
1565 }
1566 }
1567
1568 #endif
1569
1570 #else
1571
1572 int DeallocateAllImages(void)
1573 {
1574 int i;
1575 IMAGEHEADER *ihptr;
1576
1577 if (NumImages)
1578 {
1579 ihptr = ImageHeaderArray;
1580 for (i = NumImages; i!=0; i--)
1581 {
1582 DeallocateImageHeader(ihptr++);
1583 }
1584 NumImages = 0;
1585 NextFreeImageHeaderPtr = ImageHeaderArray;
1586 }
1587
1588 return Yes; /* ok for the moment */
1589 }
1590
1591 int MinimizeAllImages(void)
1592 {
1593 int i;
1594 IMAGEHEADER *ihptr;
1595
1596 if (NumImages)
1597 {
1598 ihptr = ImageHeaderArray;
1599 for (i = NumImages; i!=0; i--)
1600 {
1601 MinimizeImageHeader(ihptr++);
1602 }
1603 }
1604
1605 return Yes; /* ok for the moment */
1606 }
1607
1608 int RestoreAllImages(void)
1609 {
1610 int i;
1611 IMAGEHEADER *ihptr;
1612
1613 if (NumImages)
1614 {
1615 ihptr = ImageHeaderArray;
1616 for (i = NumImages; i!=0; i--)
1617 {
1618 RestoreImageHeader(ihptr++);
1619 }
1620 }
1621
1622 return Yes; /* ok for the moment */
1623 }
1624
1625 #endif
1626
1627
1628 #ifdef RIFF_SYSTEM
1629
1630 /*
1631 The RIFF_SYSTEM uses this function to return an image number
1632 for an image which might be already loaded. The argument
1633 passed points to the full pathname of the image that the
1634 system wants to load, so an explicit stricmp on the
1635 image names of already loaded images will suffice. To
1636 avoid loading images more than once, it ensures that the
1637 path generated for two identical images will always be
1638 the same. It also fills in the ImageName field with the
1639 fill path of images it loads.
1640
1641 Currently I am assuming that users of ImageGroups will
1642 no longer need images in group n+1 when images in group
1643 n are deleted, so I can check in all groups from 0...Current
1644 to see if the image is already loaded.
1645
1646 Jake.
1647 */
1648
1649 int GetExistingImageNum(char const * fname)
1650 {
1651 int i;
1652 IMAGEHEADER * iharrayptr;
1653
1654 #ifdef MaxImageGroups
1655
1656 int g;
1657
1658 for (g=0; g<MaxImageGroups; ++g)
1659 {
1660 for (i=0, iharrayptr = &ImageHeaderArray[g*MaxImages]; i<NumImagesArray[g]; ++i, ++iharrayptr)
1661 {
1662 if (!stricmp(iharrayptr->ImageName,fname))
1663 {
1664 if (g!=CurrentImageGroup)
1665 MarkImageInUseByGroup(g,i,CurrentImageGroup);
1666 return i+g*MaxImages;
1667 }
1668 }
1669 }
1670
1671 #else
1672
1673 for (i=0, iharrayptr = ImageHeaderArray; i<NumImages; ++i, ++iharrayptr)
1674 {
1675 if (!stricmp(iharrayptr->ImageName,fname)) return i;
1676 }
1677
1678 #endif
1679
1680 return GEI_NOTLOADED;
1681 }
1682
1683 #endif
1684
1685