#include "3dc.h" #include #include #include "inline.h" #include "module.h" #include "chnktexi.h" #include "d3d_hud.h" #define UseLocalAssert Yes #include "ourasert.h" #include "hud_layout.h" #undef textprint #define textprintOn Yes #define DHMtextprint Yes /* define to use Dave Malcolm's replacement textprint routines */ /* As specified by Roxby */ #define ClearScreenColour 1000 /* Experiment to try and fix mystery driver problems Don't set with ForceWindowsPalette on!!! Leave this on!!! On some video cards it seems necessary not only to set palette on vblanking interval, but also AFTER D3D initialisation is complete... */ #define ChangePaletteOnVBAlways Yes /* Turn on or off checking for the validity of a video mode before switching to it. Actually causes problems on some systems because the DirectDraw enumerator fails to report valid modes (although on other systems it can report ones that can't be reached, ho hum), so at least for Chris H. it needs to be turned off. NOTE THAT THIS SHOULD HAVE THE SAME SETTING AS CheckVideoModes at the start of dd_func.cpp, at least until we make it a system.h value or something else sensible... */ #define CheckVideoModes No /* externs for commonly used global variables and arrays */ extern SHAPEHEADER **mainshapelist; extern SHAPEHEADER *testpaletteshapelist[]; extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; extern int sine[]; extern int cosine[]; extern int AdaptiveHazingFlag; extern int *Global_ShapeNormals; extern int *Global_ShapePoints; extern int *ItemPointers[]; extern int ItemData[]; extern char projectsubdirectory[]; extern int WinLeftX; extern int WinRightX; extern int WinTopY; extern int WinBotY; extern int WindowRequestMode; extern int VideoRequestMode; extern int ZBufferRequestMode; extern int RasterisationRequestMode; extern int SoftwareScanDrawRequestMode; extern int DXMemoryRequestMode; extern int TotalVideoMemory; extern int NumAvailableVideoModes; extern VIDEOMODEINFO AvailableVideoModes[]; extern int memoryInitialisationFailure; extern IMAGEHEADER ImageHeaderArray[]; /* Array of Image Headers */ /* Global Variables for PC Watcom Functions and Windows 95! */ /* Timer */ long lastTickCount; unsigned char *ScreenBuffer = 0; /* Ensure initialised to Null */ unsigned char LPTestPalette[1024]; /* to cast to lp*/ int InputMode; int VideoMode; int VideoModeType; int VideoModeTypeScreen; int WindowMode; int ScanDrawMode; int ZBufferMode; int DXMemoryMode; unsigned char AttemptVideoModeRestart; VIDEORESTARTMODES VideoRestartMode; PROCESSORTYPES ProcessorType; BOOL MMXAvailable; unsigned char *TextureLightingTable = 0; unsigned char *PaletteRemapTable = 0; int NumShadingTables = 0; int NumPaletteShadingTables = 0; int FrameRate; int NormalFrameTime; int PrevNormalFrameTime; extern int CloakingPhase; /* These two are dummy values to get the DOS platform to compile */ unsigned char KeyCode; unsigned char KeyASCII; #if SuppressWarnings unsigned char *palette_tmp; static VIEWDESCRIPTORBLOCK* vdb_tmp; static SCREENDESCRIPTORBLOCK* sdb_tmp; #endif /* Keyboard */ unsigned char KeyboardInput[MAX_NUMBER_OF_INPUT_KEYS]; unsigned char GotAnyKey; /* Input communication with Windows Procedure */ /* Print system */ #if !DHMtextprint PRINTQUEUEITEM PrintQueue[MaxMessages]; int MessagesStoredThisFrame; #endif int textprintPosX; int textprintPosY; IMAGEHEADER* fontHeader; /* Added 28/11/97 by DHM: boolean for run-time switching on/off of textprint */ int bEnableTextprint = No; /* Added 28/1/98 by DHM: as above, but applies specifically to textprintXY */ int bEnableTextprintXY = Yes; /* Palette */ unsigned char PaletteBuffer[768 + 1]; /* Test Palette */ unsigned char TestPalette[768]; unsigned char TestPalette2[768]; /* KJL 11:48:45 28/01/98 - used to scale NormalFrameTime, so the game can be slowed down */ int TimeScale=65536; /* KJL 16:00:11 28/01/98 - unscaled frame time */ int RealFrameTime; int GlobalFrameCounter; int RouteFinder_CallsThisFrame; /* KJL 15:08:43 29/03/98 - added to give extra flexibility to debugging text */ int PrintDebuggingText(const char* t, ...); int ReleasePrintDebuggingText(const char* t, ...); /* IO and Other Functions for the PC */ /* Get Shape Data Function returns a pointer to the Shape Header Block */ SHAPEHEADER* GetShapeData(int shapenum) { if(shapenum>=0 && shapenum< maxshapes) { SHAPEHEADER *sptr = mainshapelist[shapenum]; return sptr; } return NULL; } /* Platform specific VDB functions for Initialisation and ShowView() */ void PlatformSpecificVDBInit(VIEWDESCRIPTORBLOCK *vdb) { #if SuppressWarnings vdb_tmp = vdb; #endif } void PlatformSpecificShowViewEntry(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb) { #if SuppressWarnings vdb_tmp = vdb; sdb_tmp = sdb; #endif } void PlatformSpecificShowViewExit(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb) { #if SuppressWarnings vdb_tmp = vdb; sdb_tmp = sdb; #endif } /* Convert UNIX to MS-DOS */ void GetDOSFilename(char *fnameptr) { while(*fnameptr) { if(*fnameptr == 0x2f) *fnameptr = 0x5c; fnameptr++; } } /* Compare two filenames. The first filename is assumed to be raw i.e. has no project subdirectory appended. The second is assumed to be ready for use. Make a copy of both strings, prefix the copy of the first with the project subdirectory and convert them to DOS format before the comparison. */ int CompareFilenameCH(char *string1, char *string2) { char *srtmp1; char *srtmp2; int slen1 = 0; int slen2 = 0; int i; char fname1[ImageNameSize]; char fname2[ImageNameSize]; #if 0 textprint(" Compare "); textprint(string1); textprint("\n"); textprint(" with "); textprint(string2); textprint("\n"); /*WaitForReturn();*/ #endif /* Make a copy of string 1, adding the project subdirectory */ srtmp1 = projectsubdirectory; srtmp2 = fname1; while(*srtmp1) *srtmp2++ = *srtmp1++; srtmp1 = string1; while(*srtmp1) *srtmp2++ = *srtmp1++; *srtmp2 = 0; /* Make a copy of string 2 */ srtmp1 = string2; srtmp2 = fname2; while(*srtmp1) *srtmp2++ = *srtmp1++; *srtmp2 = 0; /* How long are they? */ srtmp1 = fname1; while(*srtmp1++ != 0) slen1++; srtmp2 = fname2; while(*srtmp2++ != 0) slen2++; fname1[slen1] = 0; /* Term */ fname2[slen2] = 0; #if 0 textprint("slen1 = %d, ", slen1); textprint("slen2 = %d\n", slen2); #endif #if 0 textprint(" Compare "); textprint(fname1); textprint("\n"); textprint(" with "); textprint(fname2); textprint("\n"); /*WaitForReturn();*/ #endif GetDOSFilename(fname1); GetDOSFilename(fname2); if(slen1 != slen2) { /*textprint("not same\n");*/ return No; } srtmp1 = fname1; srtmp2 = fname2; #if 0 textprint(" Compare "); textprint(srtmp1); textprint("\n"); textprint(" with "); textprint(srtmp2); textprint("\n"); WaitForReturn(); #endif for(i = slen1; i!=0; i--) { if(*srtmp1++ != *srtmp2++) { /*textprint("not same\n");*/ return No; } } /*textprint("same\n");*/ return Yes; } /* Create an RGB table for "palette" "GetRemappedPaletteColour()" is an access function for this table */ #define remap_table_size (1 << (remap_table_rgb_bits * 3)) #define cprt_info No #define cprt_cnt No int NearestColour(int rs, int gs, int bs, unsigned char *palette) { int i; VECTORCH p0; VECTORCH p1; int nearest_index; int nearest_delta; int d; p0.vx = rs; p0.vy = gs; p0.vz = bs; nearest_index = 0; nearest_delta = bigint; for(i = 0; i < 256; i++) { p1.vx = palette[0]; p1.vy = palette[1]; p1.vz = palette[2]; d = FandVD_Distance_3d(&p0, &p1); if(d < nearest_delta) { nearest_delta = d; nearest_index = i; } palette += 3; } return nearest_index; } /*************************************************************************/ /*************************************************************************/ /* Initialise System and System Variables */ void InitialiseSystem() { BOOL rc; HINSTANCE hInstance = 0; int nCmdShow = 1; /* Pick up processor type */ ProcessorType = ReadProcessorType(); if ((ProcessorType == PType_PentiumMMX) || (ProcessorType == PType_Klamath) || (ProcessorType == PType_OffTopOfScale)) MMXAvailable = TRUE; else MMXAvailable = FALSE; /* Copy initial requests to current variables, subject to later modification. */ VideoMode = VideoRequestMode; WindowMode = WindowRequestMode; /* Initialise dubious restart system for ModeX emulation and other problems */ AttemptVideoModeRestart = No; VideoRestartMode = NoRestartRequired; /* Potentially a whole suite of caps functions could be sensibly called from here, to determine available sound hardware, network links, 3D hardware acceleration etc */ /* Initialise the basic Direct Draw object, find a hardware 3D capable driver if possible and appropriate, and determine what display modes, available video memory etc exist. */ #if 0 /* LINUX */ if (InitialiseDirectDrawObject() == FALSE) /* If we cannot get a video mode, fail. No point in a non debugging option for this. */ { ReleaseDirect3D(); exit(0x997799); } /* Initialise global to say whether we think there is an onboard 3D acceleration card / motherboard built-in */ TestInitD3DObject(); /* This is (HOPEFULLY!!) now the right place to put this call. Note that it is not absolutely certain that we can do test blits from DirectDraw without setting a cooperative level, however... And note also that MMX works better with the back buffer in system memory... */ TestMemoryAccess(); #endif /* Initialise main window, windows procedure etc */ rc = InitialiseWindowsSystem(hInstance, nCmdShow, WinInitFull); /* Initialise input interface */ memset((void*)KeyboardInput, No, MAX_NUMBER_OF_INPUT_KEYS); GotAnyKey = No; #if 0 /* LINUX */ /* launch Direct Input */ InitialiseDirectInput(); InitialiseDirectKeyboard(); InitialiseDirectMouse(); InitJoysticks(); #endif /* Initialise textprint system */ textprintPosX = 0; textprintPosY = 0; #if debug InitPrintQueue(); #endif #if SUPPORT_MMX SelectMMXOptions(); #endif { /* CDF 4/2/97 */ extern void ConstructOneOverSinTable(void); ConstructOneOverSinTable(); } } /* Exit the system */ void ExitSystem(void) { /* Game specific exit functions */ ExitGame(); // Added by Mark so that Direct Sound exits cleanly #if SOUND_ON ExitSoundSystem(); // In ds_func.cpp #endif /* Shaft DirectDraw and hit Direct3D with a blunt Bill. Note that ReleaseDirect3D is currently responsible for whacking DirectDraw and DirectInput as well; I should probably rename it ReleaseDirectX sometime... */ ReleaseDirect3D(); /* Kill windows procedures */ ExitWindowsSystem(); } /* Timer functions are based on Windows timer giving number of millisecond ticks since Windows was last booted. Note this will wrap round after Windows has been up continuously for approximately 49.7 days. This is not considered to be too significant a limitation... */ void ResetFrameCounter(void) { lastTickCount = timeGetTime(); /* KJL 15:03:33 12/16/96 - I'm setting NormalFrameTime too, rather than checking that it's non-zero everytime I have to divide by it, since it usually is zero on the first frame. */ NormalFrameTime = 65536 >> 4; PrevNormalFrameTime = NormalFrameTime; RealFrameTime = NormalFrameTime; FrameRate = 16; GlobalFrameCounter=0; CloakingPhase = 0; RouteFinder_CallsThisFrame=0; } void FrameCounterHandler(void) { int newTickCount = timeGetTime(); int fcnt; fcnt = newTickCount - lastTickCount; lastTickCount = newTickCount; if (fcnt == 0) fcnt = 1; /* for safety */ FrameRate = TimerFrame / fcnt; PrevNormalFrameTime = NormalFrameTime; NormalFrameTime = DIV_FIXED(fcnt,TimerFrame); RealFrameTime = NormalFrameTime; { if (TimeScale!=ONE_FIXED) { NormalFrameTime = MUL_FIXED(NormalFrameTime,TimeScale); } } /* cap NormalFrameTime if frame rate is really low */ if (NormalFrameTime>16384) NormalFrameTime=16384; GlobalFrameCounter++; CloakingPhase += NormalFrameTime>>5; RouteFinder_CallsThisFrame=0; } /* This jump table has been provided solely to ensure compatibility with DOS and other versions. */ void (*UpdateScreen[]) (void) = { FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers, FlipBuffers }; /* Wait for Return Key Such a function may not be defined on some platforms On Windows 95 the description of this function has been changed, so that it calls FlushTextprintBuffer and FlipBuffers before going into the actual WaitForReturn code. This is necessary if it is to behave in the same way after a textprint call as it does on the DOS platform. */ void WaitForReturn(void) { /* Crude but probably serviceable for now */ long SavedTickCount; SavedTickCount = lastTickCount; /* Display any lingering text */ FlushTextprintBuffer(); FlipBuffers(); while (!(KeyboardInput[KEY_CR])) DirectReadKeyboard(); lastTickCount = SavedTickCount; } /* By copying the globals here we guarantee that game functions will receive a set of input values updated at a defined time */ void ReadUserInput(void) { DirectReadMouse(); ReadJoysticks(); DirectReadKeyboard(); } /* At present all keyboard and mouse input is handled through project specific functionality in win_func, and all these functions are therefore empty. Later we may port to DirectInput, at which point we may reactivate these. */ void ReadKeyboard(void) { } void ReadMouse(void) { } /* Not NECESSARILY the standard functionality, but it seems good enough to me... */ void CursorHome(void) { /* Reset positions for textprint system */ textprintPosX = 0; textprintPosY = 0; } void GetProjectFilename(char *fname, char *image) { char *src; char *dst; src = projectsubdirectory; dst = fname; while(*src) *dst++ = *src++; src = image; while(*src) *dst++ = *src++; *dst = 0; } /* Attempts to load the image file. Returns a pointer to the image if successful, else zero. Image Header is filled out if successful, else ignore it. NOTE The pointer to the image data is also stored in the image header. */ TEXTURE* LoadImageCH(char *fname, IMAGEHEADER *iheader) { return 0; } void ConvertToDDPalette(unsigned char* src, unsigned char* dst, int length, int flags) { int i; /* Copy palette, introducing flags and shifting up to 8 bit triple */ for (i=0; ix, pDPR->y, pDPR->CharToPrint ); #else D3D_BlitWhiteChar ( pDPR->x, pDPR->y, pDPR->CharToPrint ); #endif pDPR++; } if (fTextLost) { /* Display error message in case test has been lost due to clipping of Y edge, or buffer overflow */ int i; int NumChars=strlen(TextLostMessage); for (i=0;i=0) && (y<=LastDisplayableYForChars()) ) { if (DHM_NumCharsInQueuex=x; pDPR->y=y; pDPR->CharToPrint=Ch; } else { /* Otherwise the queue if full, we will have to ignore this char; set an error flag so we get a message*/ fTextLost=Yes; } } else { /* Otherwise the text is off the top or bottom of the screen; set an error flag to get a message up*/ fTextLost=Yes; } } static int DHM_MoveBufferToQueue(int* pPosX,int* pPosY,int fZeroLeftMargin) { /* Function takes two integers by reference (using pointers), and outputs whatever is in the string buffer into the character queue, so that code can be shared by textprint() and textprintXY() Returns "number of lines": any carriage returns or word wraps */ /* PRECONDITION */ { LOWLEVELASSERT(pPosX); LOWLEVELASSERT(pPosY); } /* CODE */ { int NumLines=0; int LeftMarginX; if (fZeroLeftMargin) { LeftMarginX=0; } else { LeftMarginX=*pPosX; } /* Iterate through the string in the buffer, adding the individual characters to the queue */ { char* pCh=&TextprintBuffer[0]; int SafetyCount=0; while ( ((*pCh)!='\0') && ((SafetyCount++)LastDisplayableXForChars()) { /* Wrap around to next line.,. */ (*pPosY)+=HUD_FONT_HEIGHT; (*pPosX)=LeftMarginX; NumLines++; } } } /* ...and on to the next character*/ pCh++; } } /* Clear the string buffer */ { TextprintBuffer[0]='\0'; } return NumLines; } } int textprint(const char* t, ...) { #if (debug && textprintOn) if ( bEnableTextprint ) { /* Get message string from arguments into buffer... */ { va_list ap; va_start(ap, t); vsprintf(&TextprintBuffer[0], t, ap); va_end(ap); } /* Attempt to trap buffer overflows... */ { LOWLEVELASSERT(strlen(TextprintBuffer)ScreenDescriptorBlock.SDB_Width)) { /* Display string and reset to start of next line */ WriteStringToTextBuffer(textprintPosX, textprintPosY, &outmsg[0]); textprintPosX = 0; textprintPosY += HUD_FONT_HEIGHT; XPos=0; /* Messages can pile up at bottom of screen */ if (textprintPosY > ScreenDescriptorBlock.SDB_Height) textprintPosY = ScreenDescriptorBlock.SDB_Height; /* Clear output string and reset variables */ { int k; for (k=0; k<(j+1); k++) outmsg[k] = 0; } j = 0; /* Record number of lines output */ numlines++; } i++; } /* Flush any remaining characters */ WriteStringToTextBuffer(textprintPosX, textprintPosY, &outmsg[0]); textprintPosX = 0; textprintPosY += HUD_FONT_HEIGHT; /* Messages can pile up at bottom of screen */ if (textprintPosY > ScreenDescriptorBlock.SDB_Height) textprintPosY = ScreenDescriptorBlock.SDB_Height; numlines++; return numlines; } /* Textprint to defined location on screen (in screen coordinates for current video mode). NOTE!!! Newlines within strings sent to this function will be IGNORED. */ int textprintXY(int x, int y, const char* t, ...) { va_list ap; char message[MaxMsgChars]; va_start(ap, t); vsprintf(&message[0], t, ap); va_end(ap); WriteStringToTextBuffer(x, y, &message[0]); return 1; /* for one line */ } #else int textprint(const char* t, ...) { return 0; } int textprintXY(int x, int y, const char* t, ...) { return 0; } #endif /* Add string to text buffer */ void WriteStringToTextBuffer(int x, int y, unsigned char *buffer) { if (MessagesStoredThisFrame < MaxMessages) { strcpy(PrintQueue[MessagesStoredThisFrame].text, buffer); PrintQueue[MessagesStoredThisFrame].text_length = strlen(buffer); PrintQueue[MessagesStoredThisFrame].x = x; PrintQueue[MessagesStoredThisFrame].y = y; MessagesStoredThisFrame++; } } /* Display string of chracters, starting at passed pointer, at location on screen starting with x and y. Patched by Dave Malcolm 20/11/96 so that text wraps around when it reaches the right hand edge of the screen, in this routine, at least... */ void DisplayWin95String(int x, int y, unsigned char *buffer) { int InitialX=x; int stlen; unsigned char ch; stlen = strlen(buffer); do { ch = (unsigned char) *buffer; BlitWin95Char(x, y, ch); x += CharWidth; if (x > (ScreenDescriptorBlock.SDB_Width - CharWidth)) { #if 1 /* Wrap to new line, based on coordinates for display...*/ x=InitialX; y+=HUD_FONT_HEIGHT; #else /* Characters will pile up at screen edge */ x = (ScreenDescriptorBlock.SDB_Width - CharWidth); #endif } buffer++; stlen--; } while ((ch != '\n') && (ch != '\0') && (stlen > 0)); } /* Write all messages in buffer to screen (to be called at end of frame, after surface / execute buffer unlock in DrawItemListContents, so that text appears at the front of the back buffer immediately before the flip). */ void FlushTextprintBuffer(void) { int i; for (i=0; i> 2; *dst++ = (*src++) >> 2; *dst++ = (*src++) >> 2; } }