287 lines · 6.5 KB · C
RawDownload
#include <SDL2/SDL.h>#include <SDL2/SDL_image.h>#include <SDL2/SDL_mixer.h> #include "basis.h"#include "printsdlerror.h" /*Copyright (c) 2013-2021 Devine Lu Linvega2018 web port by rezmason2021 C89 port by rezmason Permission to use, copy, modify, and distribute this software for anypurpose with or without fee is hereby granted, provided that the abovecopyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIESWITH REGARD TO THIS SOFTWARE.*/ /* The game loop's methods are made accessible to the event watch through this type */typedef struct {	void (*resize)(int, int);	void (*update)(double, double);	void (*render)(SDL_Renderer *);} WatchContext; static SDL_Window *_window = NULL;static SDL_Renderer *_renderer = NULL; static unsigned long _now = 0;static unsigned long _start = 0;static unsigned long _last = 0;static double _totalTime = 0;static double _deltaTime = 0;static double _performanceFrequency = 1;static SDL_Event _event; static int _quitting = 0;static int _focused = 0; static intinit(int chunkSize){	int sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO;	int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;	int mixFlags = MIX_INIT_MP3; 	if(SDL_Init(sdlFlags) < 0) {		return printSDLError("SDL could not initialize.");	} 	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); 	if(IMG_Init(imgFlags) != imgFlags) {		return printSDLError("SDL_image could not initialize.");	} 	if(Mix_Init(mixFlags) != mixFlags) {		return printSDLError("SDL_mixer could not initialize.");	} 	if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY /*44100*/, MIX_DEFAULT_FORMAT, 2, chunkSize) < 0) {		return printSDLError("SDL_mixer could not initialize (Mix_OpenAudio).");	} 	return 1;} /*	When the game first initializes, this method fits its window to the screen	so that it is proportional and as wide as possible.*/static voidfitWindowToScreen(int *width, int *height){ 	SDL_DisplayMode displayMode;	if(SDL_GetCurrentDisplayMode(0, &displayMode) != 0) {		printSDLError("SDL could not get current display mode.");	} 	if(*width > displayMode.w || *height > displayMode.h) {		float aspectRatio = (float)*width / (float)*height;		float displayAspectRatio = (float)displayMode.w / (float)displayMode.h;		if(displayAspectRatio < aspectRatio) {			*width = displayMode.w / 128 * 128;			*height = *width / aspectRatio;		} else {			*height = displayMode.h / 128 * 128;			*width = *height * aspectRatio;		}	}} static intcreateWindow(char *name, int *windowW, int *windowH, int fitToScreen){	int flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; 	SDL_DestroyWindow(_window);	_window = NULL;	SDL_DestroyRenderer(_renderer);	_renderer = NULL; 	if(fitToScreen) {		fitWindowToScreen(windowW, windowH);	} 	_window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, *windowW, *windowH, flags);	if(_window == NULL) {		return printSDLError("SDL could not create a window.");	} 	_renderer = SDL_CreateRenderer(		_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);	if(_renderer == NULL) {		return printSDLError("SDL could not create a renderer.");	}	SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 0xFF); 	return 1;} static voidupdateTime(){	_last = _now;	_now = SDL_GetPerformanceCounter();	_totalTime = (double)(_now - _start) / _performanceFrequency;	_deltaTime = (double)(_now - _last) / _performanceFrequency;} /*	SDL games usually freeze when you manually resize their window.	This hack circumvents the game loop to allow us to at least	re-render the contents of the window as the player adjusts its dimensions.*/static inteventWatch(void *data, SDL_Event *event){	if(event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {		WatchContext *watchContext = data;		SDL_Delay(10);		watchContext->resize(event->window.data1, event->window.data2);		if(_focused) {#if 0				updateTime();				if(_deltaTime < 1) {					watchContext->update(_totalTime, _deltaTime);				}#endif		}		SDL_RenderClear(_renderer);		watchContext->render(_renderer);		SDL_RenderPresent(_renderer);	}	return 1;} intBasis_Init(char *name, int chunkSize, int *windowW, int *windowH, int fitToScreen){	int status = 1;	status &= init(chunkSize);	status &= createWindow(name, windowW, windowH, fitToScreen);	return status;} voidBasis_Halt(){	_quitting = 1;} voidBasis_Quit(){	Basis_Halt(); 	SDL_DestroyRenderer(_renderer);	_renderer = NULL; 	SDL_DestroyWindow(_window);	_window = NULL; 	Mix_CloseAudio();	IMG_Quit();	Mix_Quit();	SDL_Quit();} SDL_Renderer *Basis_GetRenderer(){	return _renderer;} /*	Basis_Run encapsulates a core game loop. It also supplies	the values that are then passed on to its handlers,	such as the game time, events, and the window renderer. 	Lastly, it registers the event watch for the resize hack above.*/voidBasis_Run(void (*processEvent)(SDL_Event *),	void (*resize)(int, int),	void (*update)(double, double),	void (*render)(SDL_Renderer *)){	int windowW, windowH;	WatchContext watchContext;	_performanceFrequency = (double)SDL_GetPerformanceFrequency();	_start = SDL_GetPerformanceCounter();	_quitting = 0;	_focused = 0; 	watchContext.resize = resize;	watchContext.update = update;	watchContext.render = render;	SDL_AddEventWatch(&eventWatch, &watchContext); 	SDL_GetWindowSize(_window, &windowW, &windowH);	resize(windowW, windowH); 	while(!_quitting) {		while(SDL_PollEvent(&_event) != 0) {			switch(_event.type) {			case SDL_QUIT:				_quitting = 1;				break; 			case SDL_WINDOWEVENT:				switch(_event.window.event) {				case SDL_WINDOWEVENT_SIZE_CHANGED:					resize(_event.window.data1, _event.window.data2);					break; 				case SDL_WINDOWEVENT_FOCUS_GAINED:					_focused = 1;					break; 				case SDL_WINDOWEVENT_FOCUS_LOST:					_focused = 0;					break;				}				break; 			case SDL_KEYDOWN:				if(!_event.key.repeat) {					processEvent(&_event);				}				break; 			case SDL_KEYUP:				if(!_event.key.repeat) {					processEvent(&_event);				}				break; 			case SDL_MOUSEMOTION:				processEvent(&_event);				break; 			case SDL_MOUSEBUTTONDOWN:			case SDL_MOUSEBUTTONUP:				if(_event.button.button == SDL_BUTTON_LEFT) {					processEvent(&_event);				}				break;			}		} 		if(_focused) {			updateTime();			if(_deltaTime < 1) {				update(_totalTime, _deltaTime);			}		}		SDL_RenderClear(_renderer);		render(_renderer);		SDL_RenderPresent(_renderer);	} 	SDL_DelEventWatch(&eventWatch, &watchContext);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t