about summary refs log blame commit diff stats
path: root/src/main.c
blob: 4091596e59089f8a5ef7185fc99aed5d295cbce5 (plain) (tree)
1
2
3
4
5
6
7
8
9
                 

                   
                   
                      
                        
 

                               
                                   
                               


                   
                        



                                                  
                                           
                                                                                       
                                                                                                                   
                                                                                                     


                                                                                           
                                                                                                                                         


                                                              
                                                
                                                        








                                                                                                                   
                                         





                                                                                                                            
 
               
                             






                                                  
          
                                  
                                                                   






                                                           



                                                                                                            
         
 
                  

 
                    
              


                                                          
                                                                



                                                                           



                                       
                                             


                                                
                                                                           
                                                       
                                                                        
                                                                               
                                                      
                                                                    
                                                                               
                                                      
                                                              
                                                                                
                                                      
                                                                  
                                                                                    
                                                      
                                                                 
                                                                                   
                                                      
                                                                      
                                                                    



                                                      
                                                                       
                                                   
                                                                         

                         
                                              
         
                  


                                  
                       
                                               






                                                        
                                                                 



                                     
                                                 


                    
                                  
                                      
                                                                                                                                                 
                         
                                 
                                      

                                                                                             
                         
                             



                                                     
                                    
 
                                                                 



                                       
                            
                                                                              
        


                                  
                                   
         
 
                       
                                                    
                                                                         
                                             
 
                           
                                                                   



                                                                                                   
                                                       











                                                                             
                                                     
         
        
                                      











                                                                
                             

                          
 
                                                    




                                                       
                                                                

         
                         

                                        
                                            


                                                            
                                              


                                                            

                                      
                 
         
        
                                                                    


                                            


                      
#include "pong.h"

int Difficulty = 1;
SDL_atomic_t Ticks;
bool GameGoing = true;
char VersionString[256];

struct Settings GlobalSettings;

SDL_mutex *AudioQueueBeingModified;
SDL_atomic_t AudioInitializing;

int AudioQueue[20];

void set_screen_mode() {
	ClearWindowState(FLAG_VSYNC_HINT);
	ClearWindowState(FLAG_WINDOW_TOPMOST);
	ClearWindowState(FLAG_WINDOW_UNDECORATED);
	ClearWindowState(FLAG_FULLSCREEN_MODE);
	switch(GlobalSettings.Fullscreen) {
		case 1: /* Real Fullscreen is fickle as fuck. So it needs a timeout. */
			SetWindowSize(GetMonitorWidth(GetCurrentMonitor()), GetMonitorHeight(GetCurrentMonitor()));
			int Timeout = SDL_AtomicGet(&Ticks)+300; /* Set the timeout for 5 seconds. */
			while(GetScreenHeight() != GetMonitorHeight(GetCurrentMonitor())) {
				BeginDrawing();
				EndDrawing();
				if(SDL_AtomicGet(&Ticks) >= Timeout) { /* Default to windowed if fullscreen fails for whatever reason. */
					goto FullScreenFailed;
				}
			}
			SetWindowPosition(0, 0);
			SetWindowState(FLAG_VSYNC_HINT);
			SetWindowState(FLAG_FULLSCREEN_MODE);
			break;
		case 2:
			SetWindowState(FLAG_WINDOW_TOPMOST);
			SetWindowState(FLAG_WINDOW_UNDECORATED);
			SetWindowPosition(0, 0);
			SetWindowSize(GetMonitorWidth(GetCurrentMonitor()), GetMonitorHeight(GetCurrentMonitor()));
			break;
		default:
			FullScreenFailed:
			SetWindowSize(1280, 720);
			SetWindowPosition(GetMonitorHeight(GetCurrentMonitor())/5, GetMonitorHeight(GetCurrentMonitor())/5);
			break;
	}
	return;
}

double Started;
static int internal_clock() {
	static const double Framerate = 1.0/60.0f;
	double OldTime = GetTime();
	double DeltaTime = 0;
	double NewTime = 0;
	Started = GetTime();
	struct timespec SleepFor = {
		0, 99999
	};
	while(GameGoing == true) {
		nanosleep(&SleepFor, NULL); /* Reduces CPU usage */
		NewTime = GetTime();
		DeltaTime += (NewTime - OldTime)/Framerate;
		OldTime = NewTime;
		while(DeltaTime >= 1.0) {
			SDL_AtomicAdd(&Ticks, 1);
			DeltaTime--;
		}
		/* This will make sure no matter where you are in the game, it will close when it should. */
		if (WindowShouldClose()) {
			GameGoing = false;
		}
	}

	return(0);
}

static int audio() {
	int i;
	Mix_Init(0);
	Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 1024);
	Mix_AllocateChannels(64);
	Mix_Chunk *Bounce = Mix_LoadWAV("resources/bounce.wav");
	Mix_Chunk *Victory = Mix_LoadWAV("resources/victory.wav");
	Mix_Chunk *Defeat = Mix_LoadWAV("resources/defeat.wav");
	Mix_Chunk *PlayerScore = Mix_LoadWAV("resources/score_player.wav");
	Mix_Chunk *EnemyScore = Mix_LoadWAV("resources/score_enemy.wav");
	const struct timespec Delay = {
		0, 20000000
	};
	struct timespec Remaining;
	SDL_AtomicSet(&AudioInitializing, 1);
	while(GameGoing == true) {
		for(i = 0; i < 20; i++) {
			if(AudioQueue[i] != -1){
				Mix_Volume(-1, GlobalSettings.SoundVolume);
				switch(AudioQueue[i]) {
					case 0: /* Play bounce sound. */
						Mix_PlayChannel(-1, Bounce, 0);
						break;
					case 1: /* Play game over */
						Mix_PlayChannel(-1, Defeat, 0);
						break;
					case 2: /* Play win */
						Mix_PlayChannel(-1, Victory, 0);
						break;
					case 4: /* Player Score */
						Mix_PlayChannel(-1, PlayerScore, 0);
						break;
					case 5: /* Enemy Score */
						Mix_PlayChannel(-1, EnemyScore, 0);
						break;
					case 99: /* Stop All Sounds */
						Mix_HaltChannel(-1);
						break;
					default:
						break;
				}
				SDL_LockMutex(AudioQueueBeingModified);
				AudioQueue[i] = -1;
				SDL_UnlockMutex(AudioQueueBeingModified);
			}
		}
		nanosleep(&Delay, &Remaining);
	}
	return(0);
}

bool play_audio(int SoundEffect) {
	unsigned int i;
	SDL_LockMutex(AudioQueueBeingModified);
	for(i = 1; i != 20; i++) {
		if (AudioQueue[i-1] == -1) {
			AudioQueue[i-1] = AudioQueue[i];
		}
	}
	for(i = 0; AudioQueue[i] != -1; i++) {
		if(i > sizeof(AudioQueue)) {
			SDL_UnlockMutex(AudioQueueBeingModified);
			return false;
		}
	}
	AudioQueue[i] = SoundEffect;
	SDL_UnlockMutex(AudioQueueBeingModified);
	return true;
}

int main(int argc, char *argv[]) {
	/* Credits acknowledgements */
	fprintf(stdout, "Game Icon (resources/icon.svg) by 2xYz is licensed under Creative Commons. Check docs/credits.html for more info.\n\n");
	/* Raylib Init */
	SDL_Init(SDL_INIT_AUDIO);
	InitWindow(1280, 720, "Pong");
	SDL_AtomicSet(&Ticks, 0);
	SDL_Thread *InternalClock = SDL_CreateThread(internal_clock, "Internal Clock", NULL);
	SetTargetFPS(60);
	SetExitKey(KEY_NULL);
	Image Icon = LoadImage("resources/ball.png");
	SetWindowIcon(Icon);
	SetWindowState(FLAG_VSYNC_HINT);
	SetWindowState(FLAG_WINDOW_RESIZABLE);
	SetWindowMinSize(1280, 720);

	/* Settings declaration to prevent undefined behavior. */
	GlobalSettings.Fullscreen = 0;
	GlobalSettings.SoundVolume = 0;
	GlobalSettings.MusicVolume = 0;

	/* Init Variables */
	strncpy(VersionString, "Version 0.4 - APOLLO", sizeof(VersionString));
	
	/* Populate Audio Queue */
	unsigned int i = 0;
	for(i = 0; i < 20; i++) {
		AudioQueue[i] = -1;
	}

	/* Threading */
	AudioQueueBeingModified = SDL_CreateMutex();
	SDL_Thread *AudioThread = SDL_CreateThread(audio, "Audio", NULL);
	SDL_AtomicSet(&AudioInitializing, 0);

	/* Load Settings */
	char *SettingsDirectory = SDL_GetPrefPath("iotib", "Pong");
	char SettingsFilePath[8192];
	snprintf(SettingsFilePath, sizeof(SettingsFilePath), "%s/settings.txt", SettingsDirectory);
	FILE *SettingsFile;
	reopen:
	/* Create settings file if it doesn't exist. */
	if ((SettingsFile = fopen(SettingsFilePath, "r")) == NULL) {
		if(SettingsFile != NULL) {
			fclose(SettingsFile);
		}
		if ((SettingsFile = fopen(SettingsFilePath, "w")) == NULL) {
			fprintf(stderr, "Unable to create settings file.\n");
			exit(1);
		}
		fprintf(SettingsFile, "sound_volume 100\n");
		fprintf(SettingsFile, "music_volume 100\n");
		fprintf(SettingsFile, "fullscreen 0");
		fclose(SettingsFile);
		goto reopen; /* Try opening again. */
	}
	
	/* Parse the settings file. */
	char Option[2048];
	int Value;
	while(!feof(SettingsFile)) {
		fscanf(SettingsFile, "%s %i", Option, &Value);
		if(strcmp(Option, "sound_volume") == 0) {
			GlobalSettings.SoundVolume = Value;
		} else if(strcmp(Option, "music_volume") == 0) {
			GlobalSettings.MusicVolume = Value;
		} else if(strcmp(Option, "fullscreen") == 0) {
			GlobalSettings.Fullscreen = Value;
		}
	}
	fclose(SettingsFile);
	
	set_screen_mode();

	/* Wait for audio to finish initializing. */
	struct timespec a = {
		0, 5000000
	};
	struct timespec b;
	while(SDL_AtomicGet(&AudioInitializing) == 0) {
		nanosleep(&a, &b); /* Prevent heavy cpu usage */
	}

	/* Launch Game */
	while (GameGoing == true) {
		switch(title_screen()) {
			case 0: /* Versus */
				play_audio(STOP_ALL_SOUNDS);
				versus_main();
				break;
			case 1: /* Marathon */
				play_audio(STOP_ALL_SOUNDS);
				marathon_main();
				break;
			default:
				break;
		}
	}
	
	GameGoing = false; /* Make sure the game is going to end. */
	SDL_WaitThread(InternalClock, NULL);
	SDL_WaitThread(AudioThread, NULL);
	SDL_Quit();
	CloseWindow();
	return(0);
}