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

                   
                      
                   
                     
                  

                   
                       
                              
 




                    




                                        

 

                       

                                                                

                           
 
 

                          









                                                                       
 
 

                
                                                    
                                                                                

 

                       
                                                    


                                                     



                  



                    






                                        
 


                                          
 
                       
 

                                                     




                                            
 



                                                 
 
                                                
 


                                              
 


                                          
 




                                                             
 



                                                      
 


                                                  
 

                                         
 
                                                                 
                                                                           



                                                                    
 
                                      
 


                                              
 









                                            
 


                                          
 


                 









                                                           
 
                              
 
                                        
 


                                                              

                                                                           

                                         
 





                                       

          

                                                                        
 






                                                                      








                                                       
 
                                          

                                      

 

                                
                                 
 
                                              
 
                                                     







                                 
 


                   

                                                          
 
                                                                   
                                 
                                          
 
                                          



                                                                         
 




                                                                      


                                   
                                           
                         


                                                                            

                                   
 






                                                                                


                                   




















                                                                               

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

#include <GLFW/glfw3.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 GetMouse(Point *p)
{
	double xpos, ypos;
	glfwGetCursorPos(glfwGetCurrentContext(), &xpos, &ypos);
	p->h = floor(xpos);
	p->v = floor(ypos);
}

void GetMouseRel(Point *p)
{
	const auto window = glfwGetCurrentContext();
	glfwGetWindowSize(window, &p->h, &p->v);
	p->h /= 2;
	p->v /= 2;

	double xpos, ypos;
	glfwGetCursorPos(window, &xpos, &ypos);
	glfwSetCursorPos(window, p->h, p->v); // we shouldn't need this
	p->h = floor(xpos) - p->h;
	p->v = floor(ypos) - p->v;
}

int Button(void)
{
	const auto window = glfwGetCurrentContext();
	return glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
}

bool IsKeyDown(int key)
{
	const auto window = glfwGetCurrentContext();
	return glfwGetKey(window, key) == GLFW_PRESS;
}

#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);
}