avp/3dc/win95/TEXIO.C
Rebellion Developments 218ca90543 Import Aliens vs Predator - Gold (Build 116)
Source code release, imported from:
https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code

All text files were converted to Unix format.
2019-08-19 05:45:17 +02:00

1883 lines
34 KiB
C

#if 1
#include "3dc.h"
#include <conio.h>
#include <sys\stat.h>
#include "inline.h"
#ifdef RIFF_SYSTEM
#include "chnktexi.h"
#endif
#define UseLocalAssert 0
#include "ourasert.h"
#else
#include <stdio.h>
#include <conio.h>
#include <sys\stat.h>
#include "system.h"
#include "equates.h"
#include "platform.h"
#include "shape.h"
#include "prototyp.h"
#include "inline.h"
#ifdef RIFF_SYSTEM
#include "chnktexi.h"
#endif
#endif
#include "awTexLd.h"
#include "alt_tab.h"
/*
#define for experimental purposes
ONLY!!!
*/
#define DefinedTextureType TextureTypePPM
#if 0
#if debug
int tripa = 100;
int tripb = 100;
int tripc = 0;
#define trip_up tripa = tripb / tripc;
#endif
#endif
/*
externs for commonly used global variables and arrays
*/
extern SHAPEHEADER **mainshapelist;
extern (*ShapeLanguageFunctions[])(SHAPEINSTR *shapeinstrptr);
extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
extern unsigned char *ScreenBuffer;
extern char projectsubdirectory[];
extern int ScanDrawMode;
extern int VideoModeType;
/*
Global Variables for PC Functions
*/
TEXTURE *ImageBuffer; /* Memory Resident Image Data */
#ifdef MaxImageGroups
#if MaxImageGroups < 2 /* optimize if this multiple groups are not required */
#undef MaxImageGroups
#endif /* MaxImageGroups < 2 */
#endif /* MaxImageGroups */
#ifdef MaxImageGroups
#include "txioctrl.h"
/*
basically, I want there to be more than one image header array
so that I can load some images once only, then load shapes, call
InitializeTextures, DeallocateAllImages, etc. and only the images associated
with the shapes load are deallocated.
I might want to load shapes in two blocks, calling InitializeTextures
for each load.
There will need to be as many slots for ImageHeaderArrays as MaxImageGroups
I want this to be completely invisible to anyone except programmers on
PC projects that require this feature
Jake.
*/
/* these three globals must behave the same */
int NumImages = 0; /* # current images */
IMAGEHEADER *ImageHeaderPtrs[MaxImageGroups*MaxImages]; /* Ptrs to Image Header Blocks */
IMAGEHEADER ImageHeaderArray[MaxImageGroups*MaxImages]; /* Array of Image Headers */
int NumImagesArray[MaxImageGroups]; /* must be static to ensure initialization to zero */
static int CurrentImageGroup = 0;
static IMAGEHEADER *NextFreeImageHeaderPtr[MaxImageGroups];
#else /* ! MaxImageGroups */
int NumImages = 0; /* # current images */
IMAGEHEADER *ImageHeaderPtrs[MaxImages]; /* Ptrs to Image Header Blocks */
IMAGEHEADER ImageHeaderArray[MaxImages]; /* Array of Image Headers */
static IMAGEHEADER *NextFreeImageHeaderPtr;
#endif /* ! MaxImageGroups */
/*
Initialise General Texture Data Structures and Variables
*/
#if LoadingMapsShapesAndTexturesEtc
void InitialiseImageHeaders(void)
{
#ifdef MaxImageGroups
NumImages = CurrentImageGroup * MaxImages;
NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
#else
NumImages = 0;
NextFreeImageHeaderPtr = ImageHeaderArray;
#endif
}
int LoadImageCHsForShapes(SHAPEHEADER **shapelist)
{
SHAPEHEADER **shlistptr;
SHAPEHEADER *shptr;
char **txfiles;
int TxIndex;
int LTxIndex;
/*
Build the Texture List
*/
shlistptr = shapelist;
while(*shlistptr) {
shptr = *shlistptr++;
/* If the shape has textures */
if(shptr->sh_localtextures) {
txfiles = shptr->sh_localtextures;
LTxIndex = 0;
while(*txfiles) {
/* The RIFF Image loaders have changed to support not loading the same image twice - JH 17-2-96 */
char *src;
char *dst;
char fname[ImageNameSize];
char *texfilesptr;
#ifndef RIFF_SYSTEM
int i, j, NewImage;
char *iname;
IMAGEHEADER *ihptr;
IMAGEHEADER *new_ihptr;
void* im;
#endif
txfilesptr = *txfiles++;
/*
"txfilesptr" is in the form "textures\<fname>". We need to
prefix that text with the name of the current textures path.
Soon this path may be varied but for now it is just the name of
the current project subdirectory.
*/
src = projectsubdirectory;
dst = fname;
while(*src)
*dst++ = *src++;
src = txfilesptr;
while(*src)
*dst++ = *src++;
*dst = 0;
#ifdef RIFF_SYSTEM
/* This function calls GetExistingImageHeader to figure out if the image is already loaded */
TxIndex = CL_LoadImageOnce(fname,(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RELATIVEPATH|LIO_RESTORABLE);
GLOBALASSERT(GEI_NOTLOADED != TxIndex);
#else
/* If there are already images, try and find this one */
NewImage = Yes;
#ifdef MaxImageGroups
TxIndex = CurrentImageGroup * MaxImages; /* Assume image 0 */
if(NumImagesArray[CurrentImageGroup]) {
for(i=NumImagesArray[CurrentImageGroup]; i!=0 && NewImage!=No; i--) {
#else
TxIndex = 0; /* Assume image 0 */
if(NumImages) {
for(i=NumImages; i!=0 && NewImage!=No; i--) {
#endif
ihptr = ImageHeaderPtrs[TxIndex];
iname = &ihptr->ImageName[0];
j = CompareFilenameCH(txfilesptr, iname);
if(j) NewImage = No;
else TxIndex++;
}
}
/* If this is a new image, add it */
if(NewImage) {
/* Get an Image Header */
new_ihptr = GetImageHeader();
if(new_ihptr) {
if (ScanDrawMode == ScanDrawDirectDraw)
im = (void*) LoadImageCH(&fname[0], new_ihptr);
else
im = LoadImageIntoD3DImmediateSurface
(&fname[0], new_ihptr, DefinedTextureType);
}
}
#endif
/*
The local index for this image in this shape is
"LTxIndex".
The global index for the image is "TxIndex".
We must go through the shape's items and change all the
local references to global.
*/
MakeShapeTexturesGlobal(shptr, TxIndex, LTxIndex);
LTxIndex++; /* Next Local Texture */
}
/* Is this shape a sprite that requires resizing? */
if((shptr->shapeflags & ShapeFlag_Sprite) &&
(shptr->shapeflags & ShapeFlag_SpriteResizing)) {
SpriteResizing(shptr);
}
}
}
return Yes;
}
#else
#define InitTexPrnt No
int InitialiseTextures(void)
{
SHAPEHEADER **shlistptr;
SHAPEHEADER *shptr;
char **txfiles;
int TxIndex;
int LTxIndex;
/*
Free up any currently loaded images
The caller is responsible for any other structures which might refer
to the currently loaded images
*/
#ifdef MaxImageGroups
DeallocateCurrentImages();
NumImages = CurrentImageGroup * MaxImages;
NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
#else
DeallocateAllImages();
/* Initialise Image Header Variables */
NumImages = 0;
NextFreeImageHeaderPtr = ImageHeaderArray;
#endif
/* Added 23/3/98 by DHM so that this can be called without loading any
shapes (to get textprint working in the menus):
*/
if ( NULL == mainshapelist )
{
return Yes;
// early exit
}
/* Build the Texture List */
shlistptr = &mainshapelist[0];
while(*shlistptr) {
shptr = *shlistptr++;
/* If the shape has textures */
if(shptr->sh_localtextures) {
#if InitTexPrnt
textprint("This shape has textures\n");
#endif
txfiles = shptr->sh_localtextures;
LTxIndex = 0;
while(*txfiles) {
/* The RIFF Image loaders have changed to support not loading the same image twice - JH 17-2-96 */
char *src;
char *dst;
char fname[ImageNameSize];
char *txfilesptr;
#ifndef RIFF_SYSTEM
int i, j, NewImage;
char *iname;
IMAGEHEADER *ihptr;
IMAGEHEADER *new_ihptr;
void* im;
#endif
txfilesptr = *txfiles++;
/*
"txfilesptr" is in the form "textures\<fname>". We need to
prefix that text with the name of the current textures path.
Soon this path may be varied but for now it is just the name of
the current project subdirectory.
*/
src = projectsubdirectory;
dst = fname;
while(*src)
*dst++ = *src++;
src = txfilesptr;
while(*src)
*dst++ = *src++;
*dst = 0;
#if InitTexPrnt
textprint(" A Texture\n");
#endif
#ifdef RIFF_SYSTEM
/* This function calls GetExistingImageHeader to figure out if the image is already loaded */
TxIndex = CL_LoadImageOnce(fname,(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RELATIVEPATH|LIO_RESTORABLE);
GLOBALASSERT(GEI_NOTLOADED != TxIndex);
#else
/* If there are already images, try and find this one */
NewImage = Yes;
#ifdef MaxImageGroups
TxIndex = CurrentImageGroup * MaxImages; /* Assume image 0 */
if(NumImagesArray[CurrentImageGroup]) {
for(i=NumImagesArray[CurrentImageGroup]; i!=0 && NewImage!=No; i--) {
#else
TxIndex = 0; /* Assume image 0 */
if(NumImages) {
for(i=NumImages; i!=0 && NewImage!=No; i--) {
#endif
ihptr = ImageHeaderPtrs[TxIndex];
iname = &ihptr->ImageName[0];
j = CompareFilenameCH(txfilesptr, iname);
if(j) NewImage = No;
else TxIndex++;
}
}
/* If this is a new image, add it */
if(NewImage) {
#if InitTexPrnt
textprint("New Image\n");
WaitForReturn();
#endif
/* Get an Image Header */
new_ihptr = GetImageHeader();
if(new_ihptr) {
if (ScanDrawMode == ScanDrawDirectDraw)
im = (void*) LoadImageCH(&fname[0], new_ihptr);
else
im = LoadImageIntoD3DImmediateSurface
(&fname[0], new_ihptr, DefinedTextureType);
if(im) {
#if InitTexPrnt
textprint("Load OK, NumImages = %d\n", NumImages);
WaitForReturn();
#endif
}
}
}
/* test */
#if InitTexPrnt
else textprint("Image Already Exists\n");
#endif
#endif
/*
The local index for this image in this shape is
"LTxIndex".
The global index for the image is "TxIndex".
We must go through the shape's items and change all the
local references to global.
*/
#if InitTexPrnt
textprint("\nLocal to Global for Shape\n");
#endif
MakeShapeTexturesGlobal(shptr, TxIndex, LTxIndex);
LTxIndex++; /* Next Local Texture */
}
/* Is this shape a sprite that requires resizing? */
if((shptr->shapeflags & ShapeFlag_Sprite) &&
(shptr->shapeflags & ShapeFlag_SpriteResizing)) {
SpriteResizing(shptr);
}
}
}
#if InitTexPrnt
textprint("\nFinished PP for textures\n");
WaitForReturn();
#endif
return Yes;
}
#endif
/*
This function accepts a shape header, a global texture index and a local
index. It searches through all the items that use textures and converts all
local references to a texture to global references.
The index to a texture that refers to the IMAGEHEADER pointer array is in
the low word of the colour int.
Bit #15 is set if this index refers to a local texture.
Here is an example of a textured item:
int CUBE_item3[]={
I_2dTexturedPolygon,3*vsize,0,
(3<<TxDefn) + TxLocal + 0,
7*vsize,5*vsize,1*vsize,3*vsize,
Term
};
To test for a local texture use:
if(ColourInt & TxLocal)
NOTE
The procedure is NOT reversible!
If one wishes to reconstruct the table, all the shapes and textures must be
reloaded and the initialisation function recalled.
Actually a function could be written that relates global filenames back to
local filenames, so in a sense that is not true. This function will only be
written if it is needed.
*/
void MakeShapeTexturesGlobal(SHAPEHEADER *shptr, int TxIndex, int LTxIndex)
{
int **ShapeItemArrayPtr;
POLYHEADER *ShapeItemPtr;
#if SupportBSP
SHAPEDATA_BSP_BLOCK *ShapeBSPPtr;
int num_bsp_blocks;
int j, k;
#endif
int i, txi;
/* Are the items in a pointer array? */
if(shptr->items) {
#if InitTexPrnt
textprint("Item Array\n");
#endif
ShapeItemArrayPtr = shptr->items;
for(i = shptr->numitems; i!=0; i--) {
ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++;
#if SupportZBuffering
if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ScaledSprite
|| ShapeItemPtr->PolyItemType == I_3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) {
#else
if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ScaledSprite
|| ShapeItemPtr->PolyItemType == I_3dTexturedPolygon){
#endif /* SupportZBuffering */
if(ShapeItemPtr->PolyFlags & iflag_txanim) {
MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr,
LTxIndex, TxIndex);
}
if(ShapeItemPtr->PolyColour & TxLocal) {
txi = ShapeItemPtr->PolyColour;
txi &= ~TxLocal; /* Clear Flag */
txi &= ClrTxDefn; /* Clear UV array index */
/* Is this the local index? */
if(txi == LTxIndex) {
/* Clear low word, OR in global index */
ShapeItemPtr->PolyColour &= ClrTxIndex;
ShapeItemPtr->PolyColour |= TxIndex;
}
}
}
}
}
#if SupportBSP
/* Or are they in a BSP block array? */
else if(shptr->sh_bsp_blocks) {
#if InitTexPrnt
textprint("BSP Block Array\n");
#endif
#if 0
/* Find the BSP Instruction */
ShInstrPtr = shptr->sh_instruction;
num_bsp_blocks = 0;
while(ShInstrPtr->sh_instr != I_ShapeEnd) {
if(ShInstrPtr->sh_instr == I_ShapeBSPTree) {
num_bsp_blocks = ShInstrPtr->sh_numitems;
}
ShInstrPtr++;
}
#endif
num_bsp_blocks = FindNumBSPNodes(shptr);
#if InitTexPrnt
textprint("Number of BSP blocks = %d\n", num_bsp_blocks);
#endif
if(num_bsp_blocks) {
ShapeBSPPtr = shptr->sh_bsp_blocks;
for(k=num_bsp_blocks; k!=0; k--) {
ShapeItemArrayPtr = ShapeBSPPtr->bsp_block_data;
for(j=ShapeBSPPtr->bsp_numitems; j!=0; j--) {
ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++;
#if InitTexPrnt
textprint("shape item\n");
#endif
if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ScaledSprite
|| ShapeItemPtr->PolyItemType == I_3dTexturedPolygon
|| ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) {
if(ShapeItemPtr->PolyFlags & iflag_txanim) {
MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr,
LTxIndex, TxIndex);
}
#if InitTexPrnt
textprint(" - textured\n");
#endif
if(ShapeItemPtr->PolyColour & TxLocal) {
#if InitTexPrnt
textprint(" - local index\n");
#endif
txi = ShapeItemPtr->PolyColour;
txi &= ~(TxLocal); /* Clear Flag */
txi &= ClrTxDefn; /* Clear Defn */
#if InitTexPrnt
textprint(" - is %d\n", txi);
textprint(" - LTxIndex is %d\n", LTxIndex);
#endif
/* Is this the local index? */
if(txi == LTxIndex) {
/* Clear low word, OR in global index */
ShapeItemPtr->PolyColour &= ClrTxIndex;
ShapeItemPtr->PolyColour |= TxIndex;
#if InitTexPrnt
textprint("Local %d, Global %d\n", LTxIndex, TxIndex);
#endif
}
}
}
}
ShapeBSPPtr++;
}
}
}
#endif /* SupportBSP */
/* Otherwise the shape has no item data */
}
/*
The animated texture frames each have a local image index in their frame
header structure. Convert these to global texture list indices in the same
way that the item function does.
*/
void MakeTxAnimFrameTexturesGlobal(SHAPEHEADER *sptr,
POLYHEADER *pheader,
int LTxIndex, int TxIndex)
{
TXANIMHEADER **txah_ptr;
TXANIMHEADER *txah;
TXANIMFRAME *txaf;
int **shape_textures;
int *txf_imageptr;
int texture_defn_index;
int i, txi, image;
#if 0
textprint("LTxIndex = %d, TxIndex = %d\n", LTxIndex, TxIndex);
WaitForReturn();
#endif
/* Get the animation sequence header */
shape_textures = sptr->sh_textures;
texture_defn_index = (pheader->PolyColour >> TxDefn);
txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index];
/* The first array element is the sequence shadow, which we skip here */
txah_ptr++;
/* Process the animation sequences */
while(*txah_ptr) {
/* Get the animation header */
txah = *txah_ptr++;
/* Process the animation frames */
if(txah && txah->txa_numframes) {
txaf = txah->txa_framedata;
for(i = txah->txa_numframes; i!=0; i--) {
/* Multi-View Sprite? */
if(sptr->shapeflags & ShapeFlag_MultiViewSprite) {
txf_imageptr = (int *) txaf->txf_image;
for(image = txah->txa_num_mvs_images; image!=0; image--) {
if(*txf_imageptr & TxLocal) {
txi = *txf_imageptr;
txi &= ~TxLocal; /* Clear Flag */
if(txi == LTxIndex) {
*txf_imageptr = TxIndex;
}
}
txf_imageptr++;
}
}
else {
if(txaf->txf_image & TxLocal) {
txi = txaf->txf_image;
txi &= ~TxLocal; /* Clear Flag */
if(txi == LTxIndex) {
txaf->txf_image = TxIndex;
}
}
}
txaf++;
}
}
}
}
/*
Sprite Resizing
or
An Optimisation For Sprite Images
This shape is a sprite which has requested the UV rescaling optimisation.
The UV array is resized to fit the sprite image bounding rectangle, and
after the UV array, in the space provided (don't forget that!), is a new
shape local space XY array of points which overwrite the standard values
when the shape is displayed.
*/
#define sr_print No
void SpriteResizing(SHAPEHEADER *sptr)
{
TXANIMHEADER **txah_ptr;
TXANIMHEADER *txah;
TXANIMFRAME *txaf;
int **shape_textures;
IMAGEHEADER *ihdr;
IMAGEEXTENTS e;
IMAGEEXTENTS e_curr;
IMAGEPOLYEXTENTS e_poly;
int *uvptr;
int texture_defn_index;
int **item_array_ptr;
int *item_ptr;
POLYHEADER *pheader;
int i, f;
int polypts[4 * vsize];
int *iptr;
int *iptr2;
int *mypolystart;
int *ShapePoints = *(sptr->points);
VECTOR2D cen_poly;
VECTOR2D size_poly;
VECTOR2D cen_uv_curr;
VECTOR2D size_uv_curr;
VECTOR2D cen_uv;
VECTOR2D size_uv;
VECTOR2D tv;
int *txf_imageptr;
int **txf_uvarrayptr;
int *txf_uvarray;
int image;
int num_images;
#if sr_print
textprint("\nSprite Resize Shape\n\n");
#endif
/* Get the animation sequence header */
shape_textures = sptr->sh_textures;
item_array_ptr = sptr->items; /* Assume item array */
item_ptr = item_array_ptr[0]; /* Assume only one polygon */
pheader = (POLYHEADER *) item_ptr;
/* Get the polygon points, and at the same time the extents, assuming an XY plane polygon */
e_poly.x_low = bigint;
e_poly.y_low = bigint;
e_poly.x_high = smallint;
e_poly.y_high = smallint;
iptr = polypts;
mypolystart = &pheader->Poly1stPt;
for(i = 4; i!=0; i--) {
iptr[ix] = ((VECTORCH*)ShapePoints)[*mypolystart].vx;
iptr[iy] = ((VECTORCH*)ShapePoints)[*mypolystart].vy;
iptr[iz] = ((VECTORCH*)ShapePoints)[*mypolystart].vz;
if(iptr[ix] < e_poly.x_low) e_poly.x_low = iptr[ix];
if(iptr[iy] < e_poly.y_low) e_poly.y_low = iptr[iy];
if(iptr[ix] > e_poly.x_high) e_poly.x_high = iptr[ix];
if(iptr[iy] > e_poly.y_high) e_poly.y_high = iptr[iy];
iptr += vsize;
mypolystart++;
}
/* TEST */
/*trip_up;*/
texture_defn_index = (pheader->PolyColour >> TxDefn);
txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index];
/* The first array element is the sequence shadow, which we skip here */
txah_ptr++;
/* Process the animation sequences */
while(*txah_ptr) {
/* Get the animation header */
txah = *txah_ptr++;
/* Process the animation frames */
if(txah && txah->txa_numframes) {
txaf = txah->txa_framedata;
for(f = txah->txa_numframes; f!=0; f--) {
/* Multi-View Sprite? */
if(sptr->shapeflags & ShapeFlag_MultiViewSprite) {
txf_imageptr = (int *) txaf->txf_image;
num_images = txah->txa_num_mvs_images;
txf_uvarrayptr = (int **) txaf->txf_uvdata;
}
/* A standard "Single View" Sprite has just one image */
else {
txf_imageptr = &txaf->txf_image;
num_images = 1;
txf_uvarrayptr = &txaf->txf_uvdata;
}
for(image = 0; image < num_images; image++) {
#if sr_print
textprint("image %d of %d \n", (image + 1), num_images);
#endif
/* Get the image */
ihdr = ImageHeaderPtrs[txf_imageptr[image]];
/* Get the uv array ptr */
txf_uvarray = txf_uvarrayptr[image];
/* Find the extents of the image, assuming transparency */
#if 0
FindImageExtents(ihdr, txaf->txf_numuvs, txaf->txf_uvdata, &e, &e_curr);
#else
FindImageExtents(ihdr, txaf->txf_numuvs, txf_uvarray, &e, &e_curr);
#endif
/* Convert the image extents to fixed point */
#if sr_print
textprint("extents = %d, %d\n", e.u_low, e.v_low);
textprint(" %d, %d\n", e.u_high, e.v_high);
WaitForReturn();
#endif
e.u_low <<= 16;
e.v_low <<= 16;
e.u_high <<= 16;
e.v_high <<= 16;
/*
We now have all the information needed to create a NEW UV array and a NEW
polygon points XY array.
*/
/* Centre of the polygon */
cen_poly.vx = (e_poly.x_low + e_poly.x_high) / 2;
cen_poly.vy = (e_poly.y_low + e_poly.y_high) / 2;
/* Size of the polygon */
size_poly.vx = e_poly.x_high - e_poly.x_low;
size_poly.vy = e_poly.y_high - e_poly.y_low;
/* Centre of the current cookie */
cen_uv_curr.vx = (e_curr.u_low + e_curr.u_high) / 2;
cen_uv_curr.vy = (e_curr.v_low + e_curr.v_high) / 2;
/* Size of the current cookie */
size_uv_curr.vx = e_curr.u_high - e_curr.u_low;
size_uv_curr.vy = e_curr.v_high - e_curr.v_low;
/* Centre of the new cookie */
cen_uv.vx = (e.u_low + e.u_high) / 2;
cen_uv.vy = (e.v_low + e.v_high) / 2;
/* Size of the new cookie */
size_uv.vx = e.u_high - e.u_low;
size_uv.vy = e.v_high - e.v_low;
/* Write out the new UV data */
#if 0
uvptr = txaf->txf_uvdata;
#else
uvptr = txf_uvarray;
#endif
/*
Convert the duplicate UV array to this new scale
ASSUME that the format is "TL, BL, BR, TR"
*/
uvptr[0] = e.u_low;
uvptr[1] = e.v_low;
uvptr[2] = e.u_low;
uvptr[3] = e.v_high;
uvptr[4] = e.u_high;
uvptr[5] = e.v_high;
uvptr[6] = e.u_high;
uvptr[7] = e.v_low;
/*
Create the new polygon XY array
*/
uvptr += (txaf->txf_numuvs * 2); /* Advance the pointer past the UV array */
/* Copy the polygon points (XY only) to the UV array space */
iptr = polypts;
iptr2 = uvptr;
for(i = 4; i!=0; i--) {
iptr2[0] = iptr[ix];
iptr2[1] = iptr[iy];
iptr += vsize;
iptr2 += 2;
}
/* Scale the polygon points */
iptr = uvptr;
for(i = 4; i!=0; i--) {
iptr[0] = WideMulNarrowDiv(iptr[0], size_uv.vx, size_uv_curr.vx);
iptr[1] = WideMulNarrowDiv(iptr[1], size_uv.vy, size_uv_curr.vy);
iptr += 2;
}
/* The translation vector in UV space */
tv.vx = cen_uv.vx - cen_uv_curr.vx;
tv.vy = cen_uv.vy - cen_uv_curr.vy;
/* And now in world space */
tv.vx = WideMulNarrowDiv(tv.vx, size_poly.vx, size_uv_curr.vx);
tv.vy = WideMulNarrowDiv(tv.vy, size_poly.vy, size_uv_curr.vy);
/* Translate the polygon points */
iptr = uvptr;
for(i = 4; i!=0; i--) {
iptr[0] += tv.vx;
iptr[1] += tv.vy;
iptr += 2;
}
#if sr_print
textprint(" (image done)\n");
#endif
}
#if sr_print
textprint("\n");
#endif
/* Next Texture Animation Frame */
txaf++;
}
}
}
#if sr_print
textprint("\nResize done\n\n");
#endif
}
/*
This function is for animated sprites, although it has been given an interface that would
allow anyone to call it for their own purposes. It assumes that colour 0 is transparent and
then calculates the actual maximum extents of the image.
NOTE:
The image scanned is that given by the CURRENT UV ARRAY and may therefore be smaller than
the actual image. This allows for animation sequences with frames on the same image.
*/
void FindImageExtents(IMAGEHEADER *ihdr, int numuvs, int *uvdata, IMAGEEXTENTS *e, IMAGEEXTENTS *e_curr)
{
int i;
int *uvptr;
int u, v;
int startu, endu;
int startv, endv;
/* Find the current UV extents */
e_curr->u_low = bigint;
e_curr->v_low = bigint;
e_curr->u_high = smallint;
e_curr->v_high = smallint;
uvptr = uvdata;
for(i = numuvs; i!=0; i--) {
if(uvptr[0] < e_curr->u_low) e_curr->u_low = uvptr[0];
if(uvptr[1] < e_curr->v_low) e_curr->v_low = uvptr[1];
if(uvptr[0] > e_curr->u_high) e_curr->u_high = uvptr[0];
if(uvptr[1] > e_curr->v_high) e_curr->v_high = uvptr[1];
uvptr += 2;
}
/* Look for the actual UV extents, assuming that colour 0 is transparent */
switch(VideoModeType) {
case VideoModeType_8:
{
TEXTURE *tptr = ihdr->ImagePtr;
TEXTURE texel;
/* Search for u_low and v_low */
e->u_low = bigint;
e->v_low = bigint;
startv = e_curr->v_low >> 16;
endv = e_curr->v_high >> 16;
startu = e_curr->u_low >> 16;
endu = e_curr->u_high >> 16;
for(v = startv; v <= endv; v++) {
for(u = startu; u <= endu; u++) {
texel = tptr[(v * ihdr->ImageWidth) + u];
if(texel) {
if(u < e->u_low) e->u_low = u;
if(v < e->v_low) e->v_low = v;
}
}
}
if(e->u_low == bigint) e->u_low = e_curr->u_low;
if(e->v_low == bigint) e->v_low = e_curr->v_low;
/* Search for u_high and v_high */
e->u_high = smallint;
e->v_high = smallint;
for(v = endv; v >= startv; v--) {
for(u = endu; u >= startu; u--) {
texel = tptr[(v * ihdr->ImageWidth) + u];
if(texel) {
if(u > e->u_high) e->u_high = u;
if(v > e->v_high) e->v_high = v;
}
}
}
if(e->u_high == smallint) e->u_high = e_curr->u_high;
if(e->v_high == smallint) e->v_high = e_curr->v_high;
/* TEST */
/*trip_up;*/
}
break;
case VideoModeType_15:
break;
case VideoModeType_24:
break;
case VideoModeType_8T:
break;
}
}
/*
Return a pointer to the next image header
*/
IMAGEHEADER* GetImageHeader(void)
{
IMAGEHEADER *iheader;
#ifdef MaxImageGroups
/* NumImages always points to the correct point in the array */
do
{
iheader = NextFreeImageHeaderPtr[CurrentImageGroup]++;
}
while (IsImageInUse(CurrentImageGroup,NumImagesArray[CurrentImageGroup]++) ? ++NumImages : 0);
GLOBALASSERT(NumImagesArray[CurrentImageGroup] < MaxImages);
#else
iheader = NextFreeImageHeaderPtr++;
GLOBALASSERT(NumImages < MaxImages);
#endif
/* ensure flags are zero */
memset(iheader,0,sizeof(IMAGEHEADER));
ImageHeaderPtrs[NumImages] = iheader;
NumImages++;
return iheader;
}
/*
Return the address of a texture image in memory, else null
*/
#if 0
void* GetTexture(int texindex)
{
/* Ahem... */
return No;
}
#endif
/*
Allocate memory for a Texture Image
*/
#if 0
TEXTURE* GetTextureMemory(int txsize)
{
/* Err... */
return No;
}
#endif
/*
Deallocate memory for a Texture Image
*/
#if 0
void ReturnTextureMemory(TEXTURE *txptr)
{
}
#endif
static void DeallocateImageHeader(IMAGEHEADER * ihptr)
{
if (ihptr->hBackup)
{
if (ihptr->DDSurface)
{
GLOBALASSERT(!ihptr->D3DTexture);
ATRemoveSurface(ihptr->DDSurface);
}
else if (ihptr->D3DTexture)
{
GLOBALASSERT(!ihptr->DDSurface);
ATRemoveTexture(ihptr->D3DTexture);
}
AwDestroyBackupTexture(ihptr->hBackup);
ihptr->hBackup = 0;
}
if (ihptr->ImagePtr)
{
DeallocateMem(ihptr->ImagePtr);
ihptr->ImagePtr = 0;
}
if (ihptr->DDSurface)
{
ReleaseDDSurface(ihptr->DDSurface);
ihptr->DDSurface = (void*) 0;
}
if (ihptr->D3DTexture)
{
ReleaseD3DTexture(ihptr->D3DTexture);
ihptr->D3DTexture = (void*) 0;
ihptr->D3DHandle = (void*) 0;
}
}
static void MinimizeImageHeader(IMAGEHEADER * ihptr)
{
if (ihptr->DDSurface)
{
ReleaseDDSurface(ihptr->DDSurface);
ihptr->DDSurface = (void*) 0;
}
if (ihptr->D3DTexture)
{
ReleaseD3DTexture(ihptr->D3DTexture);
ihptr->D3DTexture = (void*) 0;
ihptr->D3DHandle = (void*) 0;
}
}
static void RestoreImageHeader(IMAGEHEADER * ihptr)
{
if (ScanDrawDirectDraw != ScanDrawMode)
ReloadImageIntoD3DImmediateSurface(ihptr);
}
#ifdef MaxImageGroups
void SetCurrentImageGroup(unsigned int group)
{
GLOBALASSERT(group < MaxImageGroups);
CurrentImageGroup = group;
NumImages = group*MaxImages + NumImagesArray[group];
}
int DeallocateCurrentImages(void)
{
int i;
IMAGEHEADER *ihptr;
if (NumImagesArray[CurrentImageGroup])
{
ihptr = &ImageHeaderArray[CurrentImageGroup*MaxImages];
for (i = 0; i < NumImagesArray[CurrentImageGroup]; ++i)
{
if (CanDeleteImage(CurrentImageGroup,i))
DeallocateImageHeader(ihptr);
++ihptr;
}
NumImagesArray[CurrentImageGroup] = 0;
NumImages = CurrentImageGroup * MaxImages;
NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
ImageGroupFreed(CurrentImageGroup);
}
return Yes; /* ok for the moment */
}
void NowDeleteImage(int img_group, int img_num_offset)
{
DeallocateImageHeader(&ImageHeaderArray[img_group*MaxImages+img_num_offset]);
}
int DeallocateAllImages(void)
{
int i, j;
IMAGEHEADER *ihptr;
for (j=0; j<MaxImageGroups; ++j)
{
if (NumImagesArray[j])
{
ihptr = &ImageHeaderArray[j*MaxImages];
for (i = 0; i<NumImagesArray[j]; ++i)
{
if (CanDeleteImage(j,i))
DeallocateImageHeader(ihptr);
++ihptr;
}
NumImagesArray[j] = 0;
}
ImageGroupFreed(j);
}
NumImages = CurrentImageGroup * MaxImages;
NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages];
return Yes; /* ok for the moment */
}
static void MinimizeImageCallback(int i, void * gP)
{
int g = *(int *)gP;
MinimizeImageHeader(ImageHeaderPtrs[g*MaxImages+i]);
}
int MinimizeAllImages(void)
{
int i, j;
IMAGEHEADER *ihptr;
for (j=0; j<MaxImageGroups; ++j)
{
if (NumImagesArray[j])
{
ihptr = &ImageHeaderArray[j*MaxImages];
for (i = 0; i<NumImagesArray[j]; ++i)
{
MinimizeImageHeader(ihptr);
++ihptr;
}
}
EnumLeftoverImages(j,NumImagesArray[j],MinimizeImageCallback,&j);
}
return Yes; /* ok for the moment */
}
static void RestoreImageCallback(int i, void * gP)
{
int g = *(int *)gP;
RestoreImageHeader(ImageHeaderPtrs[g*MaxImages+i]);
}
int RestoreAllImages(void)
{
int i, j;
IMAGEHEADER *ihptr;
for (j=0; j<MaxImageGroups; ++j)
{
if (NumImagesArray[j])
{
ihptr = &ImageHeaderArray[j*MaxImages];
for (i = 0; i<NumImagesArray[j]; ++i)
{
RestoreImageHeader(ihptr);
++ihptr;
}
}
EnumLeftoverImages(j,NumImagesArray[j],RestoreImageCallback,&j);
}
return Yes; /* ok for the moment */
}
#if debug
struct ImageGroupDebugInfo
{
int num_texels;
int num_images;
int num_shared;
int num_leftover;
};
static struct ImageGroupDebugInfo db_gp_info[MaxImageGroups];
static void DbShareImgCallback(int imgnum, void * user)
{
int g = *(int *)user;
++db_gp_info[g].num_shared;
}
static void DbLeftoverImgCallback(int i, void * user)
{
int g = *(int *)user;
++db_gp_info[g].num_leftover;
db_gp_info[g].num_texels += ImageHeaderPtrs[g*MaxImages+i]->ImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight;
}
void ImageGroupsDebugPrintInit(void)
{
int g;
for (g=0; g<MaxImageGroups; g++)
{
int i;
db_gp_info[g].num_texels = 0;
db_gp_info[g].num_images = NumImagesArray[g];
db_gp_info[g].num_shared = 0;
db_gp_info[g].num_leftover = 0;
EnumSharedImages(g,NumImagesArray[g],DbShareImgCallback,&g);
EnumLeftoverImages(g,NumImagesArray[g],DbLeftoverImgCallback,&g);
for (i=0; i<NumImagesArray[g]; ++i)
{
db_gp_info[g].num_texels += ImageHeaderPtrs[g*MaxImages+i]->ImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight;
}
}
}
void ImageGroupsDebugPrint(void)
{
int g;
textprint("IMAGE GROUP DEBUG INFO\nGP N_IMG N_SHR N_LFT N_TEXELS\n");
for (g=0; g<MaxImageGroups; ++g)
{
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);
}
}
#endif
#else
int DeallocateAllImages(void)
{
int i;
IMAGEHEADER *ihptr;
if (NumImages)
{
ihptr = ImageHeaderArray;
for (i = NumImages; i!=0; i--)
{
DeallocateImageHeader(ihptr++);
}
NumImages = 0;
NextFreeImageHeaderPtr = ImageHeaderArray;
}
return Yes; /* ok for the moment */
}
int MinimizeAllImages(void)
{
int i;
IMAGEHEADER *ihptr;
if (NumImages)
{
ihptr = ImageHeaderArray;
for (i = NumImages; i!=0; i--)
{
MinimizeImageHeader(ihptr++);
}
}
return Yes; /* ok for the moment */
}
int RestoreAllImages(void)
{
int i;
IMAGEHEADER *ihptr;
if (NumImages)
{
ihptr = ImageHeaderArray;
for (i = NumImages; i!=0; i--)
{
RestoreImageHeader(ihptr++);
}
}
return Yes; /* ok for the moment */
}
#endif
#ifdef RIFF_SYSTEM
/*
The RIFF_SYSTEM uses this function to return an image number
for an image which might be already loaded. The argument
passed points to the full pathname of the image that the
system wants to load, so an explicit stricmp on the
image names of already loaded images will suffice. To
avoid loading images more than once, it ensures that the
path generated for two identical images will always be
the same. It also fills in the ImageName field with the
fill path of images it loads.
Currently I am assuming that users of ImageGroups will
no longer need images in group n+1 when images in group
n are deleted, so I can check in all groups from 0...Current
to see if the image is already loaded.
Jake.
*/
int GetExistingImageNum(char const * fname)
{
int i;
IMAGEHEADER * iharrayptr;
#ifdef MaxImageGroups
int g;
for (g=0; g<MaxImageGroups; ++g)
{
for (i=0, iharrayptr = &ImageHeaderArray[g*MaxImages]; i<NumImagesArray[g]; ++i, ++iharrayptr)
{
if (!stricmp(iharrayptr->ImageName,fname))
{
if (g!=CurrentImageGroup)
MarkImageInUseByGroup(g,i,CurrentImageGroup);
return i+g*MaxImages;
}
}
}
#else
for (i=0, iharrayptr = ImageHeaderArray; i<NumImages; ++i, ++iharrayptr)
{
if (!stricmp(iharrayptr->ImageName,fname)) return i;
}
#endif
return GEI_NOTLOADED;
}
#endif