aboutsummaryrefslogblamecommitdiff
path: root/src/Support.cpp
blob: 33794d96155db2185f4e43e45264b12f224e96cc (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                   
                      
                   
                     
                  

                   

                              
 




                    




                                        

 
                                               


                                                                     
                               

                                                   
 

                       

              
 
                                  
 

                 
 
 



                          
 
                                          
 


                 

                
                                                               

 

                                                       
                                                                          
                           

 



                  



                    






                                        
 


                                          
 
                       
 

                                                     




                                            
 



                                                 
 
                                                
 


                                              
 


                                          
 




                                                             
 



                                                      
 


                                                  
 

                                         
 
                                                                 
                                                                           



                                                                    
 
                                      
 


                                              
 









                                            
 


                                          
 


                 









                                                           
 
                              
 
                                        
 


                                                              

                                                                           

                                         
 





                                       

          

                                                                        
 






                                                                      








                                                       
 
                                          

                                      

 

                                
                                 
 
                                              
 
                                                     







                                 
 


                   

                                                          
 
                                                                   
                                 
                                          
 
                                          



                                                                         
 




                                                                      


                                   
                                           
                         


                                                                            

                                   
 






                                                                                


                                   




















                                                                               

                                   
 
                   
                      
                                             
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <SDL/SDL.h>
#include <vorbis/vorbisfile.h>

#include "Support.h"
#include "Files.h"

int Random()
{
#if RAND_MAX >= 65535
	return (rand() % 65535) - 32767;
#else
#error please fix this for your platform
#endif
}

void Microseconds(UnsignedWide *microTickCount)
{
	/* NOTE: hi isn't used in BS, so it's not implemented here */
	/* TODO: does game need microsecond precision? */
	microTickCount->hi = 0;
	microTickCount->lo = SDL_GetTicks() * 1000;
}

void GetMouse(Point *p)
{
	int x;
	int y;

	SDL_GetMouseState(&x, &y);

	p->h = x;
	p->v = y;
}

void GetMouseRel(Point *p)
{
	int x;
	int y;

	SDL_GetRelativeMouseState(&x, &y);

	p->h = x;
	p->v = y;
}
int Button(void)
{
	return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(1));
}

void MoveMouse(int xcoord, int ycoord, Point *mouseloc)
{
	/* TODO: mouse warp is annoying when we can just grab the mouse */
	GetMouse(mouseloc);
}

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef MAX_PATH
#define MAX_PATH 256
#endif

static int find_filename(char *filename)
{
	char *ptr;
	char *cur;
	char *next;
	DIR *dir;
	struct dirent *dirent;

	if (access(filename, R_OK) == 0) {
		return 1;
	}

	ptr = filename;

	while (*ptr) {
		if (ptr == filename || *ptr == '/') {
			if (*ptr == '/') {
				cur = ptr+1;
			} else {
				cur = ptr;
			}

			if (*cur == 0) {
				/* hit the end */
				break;
			}

			next = strchr(cur, '/');

			if (ptr != filename) {
				*ptr = 0;
			}

			if (next) {
				*next = 0;
			}

			if (ptr == filename && *ptr == '/') {
				dir = opendir("/");
			} else {
				dir = opendir(filename);
			}

			if (dir == NULL) {
				if (ptr != filename) {
					*ptr = '/';
				}

				if (next) {
					*next = 0;
				}

				return 0;
			}

			while ((dirent = readdir(dir)) != NULL) {
				if (strcasecmp(cur, dirent->d_name) == 0) {
					strcpy(cur, dirent->d_name);
					break;
				}
			}

			closedir(dir);

			if (ptr != filename) {
				*ptr = '/';
			}

			if (next) {
				*next = '/';
				ptr = next;
			} else {
				ptr++;
			}
		} else {
			ptr++;
		}
	}

	if (access(filename, R_OK) == 0) {
		return 1;
	}

	return 0;
}

static void fix_filename(const char *original, char *fixed)
{
	const char *start;
	int i;
	int len;

	start = original;
	if (original[0] == ':') {
		start = &original[1];
	}

	fixed[MAX_PATH-1] = 0;

	strncpy(fixed, start, MAX_PATH);

	/* check to see if strncpy overwrote the terminator */
	if (fixed[MAX_PATH-1] != 0) {
		fixed[MAX_PATH-1] = 0;

		fprintf(stderr, "ERROR: file truncation error: %s -> %s\n",
			original, fixed);
	}

	len = strlen(fixed);
	for (i = 0; i < len; i++) {
		if (fixed[i] == ':') {
			fixed[i] = '/';
		}
	}

	/*
	   here we would try to see if the file is available (game dir),
	   else try another dir

	   really, this function also needs a flag to indicate whether
	   it should only go to local (write) or both (read)
	 */

	if (find_filename(fixed) == 0) {
		fprintf(stderr, "find failed: %s\n", fixed);
	}
}

/*
Convenient Filename Hacks
*/

FILE *cfh_fopen(const char *filename, const char *mode)
{
	char filename1[MAX_PATH];

	fix_filename(filename, filename1);

	return fopen(filename1, mode);
}

int Files::OpenFile(Str255 Name)
{
	char filename1[MAX_PATH];

	fix_filename((char *)Name, filename1);

	sFile = open(filename1, O_RDONLY | O_BINARY);
	return sFile;
}

void Files::EndLoad()
{
	if (sFile != -1) {
		FSClose( sFile );
	}

	sFile = -1;
}

/* Read the requested Ogg file and load it into OpenAL */
void loadOgg(char *filename, ALuint buffer, ALuint source)
{
	/* Try to find the real file (and place it in filename1) */
	char filename1[MAX_PATH];
	fix_filename(filename, filename1);

	FILE* fp = fopen(filename1, "rb");
	if (fp == NULL) {
		fprintf(stderr, "ERROR: unable to open %s\n", filename1);
		exit(EXIT_FAILURE);
	}

	OggVorbis_File vf;
	int error = -ov_open(fp, &vf, NULL, 0);
	if (error > 0) {
		fprintf(stderr, "ERROR: vorbis error %d opening %s\n",
			error, filename1);
		exit(EXIT_FAILURE);
	}

	vorbis_info* vi = ov_info(&vf, -1);
	if (vi == NULL) {
		fprintf(stderr,
			"ERROR: vorbis error opening %s (ov_info failed)\n",
			filename1);
		exit(EXIT_FAILURE);
	}

	/* Hack around some possible ogg vorbis weirdness */
	ALsizei size = vi->channels * 2 * ov_pcm_total(&vf, -1);
	ALvoid* data = malloc(((size + 2047) / 2048 + 1) * 2048);
	if (data == NULL) {
		fprintf(stderr,
			"ERROR: could not allocate %d bytes while loading %s\n",
			size, filename1);
		exit(EXIT_FAILURE);
	}

	char* i = (char*) data;
	int section;
	long ret;
#if BYTE_ORDER == BIG_ENDIAN
	while (ret = ov_read(&vf, i, 1024, 1, 2, 1, &section))
#else
	while (ret = ov_read(&vf, i, 1024, 0, 2, 1, &section))
#endif
		if (ret > 0) /* XXX: How about negative ret? */
			i += ret;

	switch (vi->channels) {
	case 1:
		alBufferData(buffer, AL_FORMAT_MONO16, data, size, vi->rate);
		break;
	case 2:
		alBufferData(buffer, AL_FORMAT_STEREO16, data, size, vi->rate);
		break;
	default:
		fprintf(stderr, "ERROR: ogg %s has %d channels\n",
			filename1, vi->channels);
		exit(EXIT_FAILURE);
	}

	free(data);
	ov_clear(&vf);
	alSourcei(source, AL_BUFFER, buffer);
}