Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,569 @@
|
||||
#include "os/glfw_driver.h"
|
||||
#include "compat/misc.h"
|
||||
#include "compat/gl.h"
|
||||
#include "main/game_platform.h"
|
||||
#include "main/references.h"
|
||||
#include "main/logging.h"
|
||||
#include "threads.h"
|
||||
#include "vec2.h"
|
||||
#include <list>
|
||||
#include <math.h>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef WIN_MODE
|
||||
#include <sys/time.h>
|
||||
#include <random>
|
||||
#else
|
||||
|
||||
//Undef duplicate macros from glfw
|
||||
#undef APIENTRY
|
||||
#undef WINGDIAPI
|
||||
|
||||
#include <Windows.h>
|
||||
#include <WinCrypt.h>
|
||||
#include "os/resource.h"
|
||||
#endif
|
||||
|
||||
//We use std::max instead
|
||||
#undef max
|
||||
|
||||
extern bool game_running;
|
||||
|
||||
namespace os {
|
||||
|
||||
void redirectWindowClose(GLFWwindow*);
|
||||
void redirectWindowResize(GLFWwindow*,int, int);
|
||||
void redirectSpecialKey(GLFWwindow*,int key, int scan, int action, int mods);
|
||||
void redirectCharKey(GLFWwindow*,unsigned);
|
||||
void redirectMouseButton(GLFWwindow*,int button, int action, int mods);
|
||||
void redirectMouseMove(GLFWwindow*,double x, double y);
|
||||
void redirectMouseWheel(GLFWwindow*,double x, double y);
|
||||
void trackMouseOver(GLFWwindow*,int over);
|
||||
void glfwError(int, const char*);
|
||||
|
||||
class GLFWDriver;
|
||||
GLFWDriver* driver = 0;
|
||||
|
||||
class GLFWDriver : public OSDriver {
|
||||
union Callback {
|
||||
std::function<bool(void)>* f_v;
|
||||
std::function<bool(int)>* f_i;
|
||||
std::function<bool(int,int)>* f_ii;
|
||||
|
||||
Callback(decltype(f_v) p_f_v) : f_v(p_f_v) {}
|
||||
Callback(decltype(f_i) p_f_i) : f_i(p_f_i) {}
|
||||
Callback(decltype(f_ii) p_f_ii) : f_ii(p_f_ii) {}
|
||||
};
|
||||
|
||||
std::list<Callback> callbacks[OSC_COUNT];
|
||||
GLFWwindow* window;
|
||||
|
||||
public:
|
||||
#ifndef WIN_MODE
|
||||
timeval start_time;
|
||||
#else
|
||||
ULARGE_INTEGER start_time;
|
||||
|
||||
LARGE_INTEGER start_time_hq, start_time_hq_freq;
|
||||
#endif
|
||||
|
||||
bool mouseOver;
|
||||
bool canLock, shouldLock;
|
||||
|
||||
double frameTime, gameTime, gameSpeed;
|
||||
|
||||
GLFWDriver() : window(0), mouseOver(true), canLock(false), shouldLock(false) {
|
||||
glfwSetErrorCallback(glfwError);
|
||||
glfwInit();
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
~GLFWDriver() {
|
||||
driver = 0;
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
bool systemRandom(unsigned char* buffer, unsigned bytes) {
|
||||
#ifdef WIN_MODE
|
||||
HCRYPTPROV provider;
|
||||
|
||||
//Attempt to acquire the context if it exists, then make it if it does not
|
||||
BOOL ctx = CryptAcquireContext(&provider, "SR2SysRand", NULL, PROV_RSA_AES, NULL);
|
||||
if(!ctx)
|
||||
ctx = CryptAcquireContext(&provider, "SR2SysRand", NULL, PROV_RSA_AES, CRYPT_NEWKEYSET);
|
||||
|
||||
if(ctx) {
|
||||
BOOL success = CryptGenRandom(provider, bytes, buffer);
|
||||
CryptReleaseContext(provider, NULL);
|
||||
|
||||
return success != 0;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
std::random_device rd;
|
||||
for(unsigned i = 0; i < bytes; ++i)
|
||||
buffer[i] = (unsigned char)rd();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setVerticalSync(int waitFrames) {
|
||||
glfwSwapInterval(waitFrames);
|
||||
}
|
||||
|
||||
void swapBuffers(double minWait_s) {
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
if(devices.cloud)
|
||||
devices.cloud->update();
|
||||
|
||||
double waitTill = frameTime + minWait_s;
|
||||
double curTime = getAccurateTime();
|
||||
|
||||
while(curTime < waitTill) {
|
||||
glfwPollEvents();
|
||||
if(devices.cloud)
|
||||
devices.cloud->update();
|
||||
threads::sleep(0);
|
||||
curTime = getAccurateTime();
|
||||
}
|
||||
|
||||
if(gameSpeed > 0 && game_running) {
|
||||
double delta = curTime - frameTime;
|
||||
if(delta > 0.5)
|
||||
delta = 0.5;
|
||||
gameTime += delta * gameSpeed;
|
||||
}
|
||||
|
||||
frameTime = curTime;
|
||||
}
|
||||
|
||||
void handleEvents(unsigned minWait_ms) {
|
||||
glfwPollEvents();
|
||||
frameTime = getAccurateTime();
|
||||
threads::sleep(minWait_ms);
|
||||
}
|
||||
|
||||
void getDesktopSize(unsigned& width, unsigned& height) {
|
||||
auto* primary = glfwGetPrimaryMonitor();
|
||||
if(primary == nullptr) {
|
||||
width = 1280;
|
||||
height = 720;
|
||||
return;
|
||||
}
|
||||
auto& desktop = *glfwGetVideoMode(primary);
|
||||
width = desktop.width;
|
||||
height = desktop.height;
|
||||
}
|
||||
|
||||
void createWindow(WindowData& data) {
|
||||
glfwWindowHint(GLFW_SAMPLES, data.aa_samples);
|
||||
glfwWindowHint(GLFW_REFRESH_RATE, data.refreshRate);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
|
||||
GLFWmonitor* monitor = nullptr;
|
||||
if(data.mode == WM_Fullscreen) {
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
|
||||
if(!data.targetMonitor.empty()) {
|
||||
int count = 0;
|
||||
GLFWmonitor** monitors = glfwGetMonitors(&count);
|
||||
for(int i = 0; i < count; ++i) {
|
||||
if(data.targetMonitor == glfwGetMonitorName(monitors[i])) {
|
||||
monitor = monitors[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(monitor && !data.overrideMonitor) {
|
||||
int count = 0;
|
||||
const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
|
||||
bool match = false;
|
||||
for(int i = 0; i < count; ++i) {
|
||||
auto& mode = modes[i];
|
||||
if(mode.width == data.width && mode.height == data.height && (data.refreshRate == 0 || data.refreshRate == mode.refreshRate)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!match) {
|
||||
monitor = nullptr;
|
||||
data.mode = WM_Window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(data.mode != WM_Fullscreen && (data.width == 0 || data.height == 0)) {
|
||||
GLFWmonitor* primary = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primary);
|
||||
|
||||
data.width = mode->width;
|
||||
data.height = mode->height;
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(data.width, data.height, "Star Ruler 2", monitor, nullptr);
|
||||
|
||||
if(window == 0)
|
||||
window = glfwCreateWindow(1024,768, "Star Ruler 2 - Error Creating Window", nullptr, nullptr);
|
||||
|
||||
if(window == 0) {
|
||||
error("Could not create window.");
|
||||
return;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
glfwGetWindowSize(window, &win_width, &win_height);
|
||||
glfwSwapInterval( data.verticalSync );
|
||||
|
||||
if(data.mode == WM_Fullscreen)
|
||||
setCursorVisible(true);
|
||||
|
||||
glfwSetWindowCloseCallback(window, redirectWindowClose);
|
||||
glfwSetWindowSizeCallback(window, redirectWindowResize);
|
||||
glfwSetKeyCallback(window, redirectSpecialKey);
|
||||
glfwSetCharCallback(window, redirectCharKey);
|
||||
glfwSetMouseButtonCallback(window, redirectMouseButton);
|
||||
glfwSetScrollCallback(window, redirectMouseWheel);
|
||||
glfwSetCursorPosCallback(window, redirectMouseMove);
|
||||
glfwSetCursorEnterCallback(window, trackMouseOver);
|
||||
|
||||
#ifdef WIN_MODE
|
||||
HICON hSmallIcon = (HICON) LoadImage ( 0, "sr2.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE | LR_DEFAULTCOLOR );
|
||||
SendMessage ( GetActiveWindow(), WM_SETICON, ICON_SMALL, (long)hSmallIcon );
|
||||
#endif
|
||||
}
|
||||
|
||||
void getVideoModes(std::vector<OSDriver::VideoMode>& output) {
|
||||
int count = 0;
|
||||
const GLFWvidmode* modes;
|
||||
auto* primary = glfwGetPrimaryMonitor();
|
||||
if(primary)
|
||||
modes = glfwGetVideoModes(primary, &count);
|
||||
output.reserve(count);
|
||||
output.resize(0);
|
||||
|
||||
std::set<uint64_t> sizes;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
VideoMode m;
|
||||
auto& mode = modes[i];
|
||||
m.width = mode.width;
|
||||
m.height = mode.height;
|
||||
m.refresh = mode.refreshRate;
|
||||
|
||||
uint64_t size = (uint64_t)m.width << 16 | (uint64_t)m.height | ((uint64_t)mode.refreshRate << 32);
|
||||
|
||||
if(sizes.find(size) == sizes.end()) {
|
||||
sizes.insert(size);
|
||||
output.push_back(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getMonitorNames(std::vector<std::string>& output) {
|
||||
int count = 0;
|
||||
GLFWmonitor** monitors = glfwGetMonitors(&count);
|
||||
output.resize(count);
|
||||
for(int i = 0; i < count; ++i)
|
||||
output[i] = glfwGetMonitorName(monitors[i]);
|
||||
}
|
||||
|
||||
bool isWindowFocused() override {
|
||||
return glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
|
||||
}
|
||||
|
||||
bool isWindowMinimized() override {
|
||||
return glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0;
|
||||
}
|
||||
|
||||
void flashWindow() override {
|
||||
glfwFlashWindow(window);
|
||||
}
|
||||
|
||||
bool isMouseOver() {
|
||||
return mouseOver;
|
||||
}
|
||||
|
||||
void setClipboard(const std::string& text) {
|
||||
glfwSetClipboardString(window, text.c_str());
|
||||
}
|
||||
|
||||
std::string getClipboard() {
|
||||
const char* str = glfwGetClipboardString(window);
|
||||
if(str)
|
||||
return std::string(str);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
int getCharForKey(int key) {
|
||||
return glfwGetCharForKey(key);
|
||||
}
|
||||
|
||||
int getKeyForChar(unsigned char chr) {
|
||||
return glfwGetKeyForChar(chr);
|
||||
}
|
||||
|
||||
unsigned getDoubleClickTime() const {
|
||||
#ifdef _MSC_VER
|
||||
return GetDoubleClickTime();
|
||||
#else
|
||||
//TODO: Get user's setting on linux
|
||||
return 200;
|
||||
#endif
|
||||
}
|
||||
|
||||
void getLastMousePos(int& x, int& y) {
|
||||
x = mouse_x;
|
||||
y = mouse_y;
|
||||
}
|
||||
|
||||
void getMousePos(int& x, int& y) {
|
||||
double dx, dy;
|
||||
glfwGetCursorPos(window, &dx,&dy);
|
||||
x = (int)floor(dx);
|
||||
y = (int)floor(dy);
|
||||
}
|
||||
|
||||
void setMousePos(int x, int y) {
|
||||
glfwSetCursorPos(window, x,y);
|
||||
}
|
||||
|
||||
void setCursorVisible(bool visible) {
|
||||
glfwSetInputMode(window, GLFW_CURSOR, visible ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
|
||||
void setCursorLocked(bool locked) {
|
||||
if(canLock == locked)
|
||||
return;
|
||||
canLock = locked;
|
||||
if(shouldLock) {
|
||||
if(locked)
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
|
||||
else
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
void setCursorShouldLock(bool locked) {
|
||||
if(shouldLock == locked)
|
||||
return;
|
||||
shouldLock = locked;
|
||||
if(canLock) {
|
||||
if(locked)
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
|
||||
else
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
void sleep(int milliseconds) {
|
||||
threads::sleep(milliseconds);
|
||||
}
|
||||
|
||||
void resetTimer() {
|
||||
#ifndef WIN_MODE
|
||||
gettimeofday(&start_time, 0);
|
||||
#else
|
||||
FILETIME cur_time;
|
||||
GetSystemTimeAsFileTime(&cur_time);
|
||||
start_time.HighPart = cur_time.dwHighDateTime;
|
||||
start_time.LowPart = cur_time.dwLowDateTime;
|
||||
|
||||
QueryPerformanceFrequency(&start_time_hq_freq);
|
||||
QueryPerformanceCounter(&start_time_hq);
|
||||
#endif
|
||||
frameTime = 0.0;
|
||||
resetGameTime(0);
|
||||
}
|
||||
|
||||
int getTime() const {
|
||||
#ifndef WIN_MODE
|
||||
timeval cur_time;
|
||||
gettimeofday(&cur_time, 0);
|
||||
|
||||
return (int)(
|
||||
1000 * (cur_time.tv_sec - start_time.tv_sec)
|
||||
+ (cur_time.tv_usec - start_time.tv_usec) / 1000);
|
||||
#else
|
||||
|
||||
FILETIME cur_ftime;
|
||||
GetSystemTimeAsFileTime(&cur_ftime);
|
||||
ULARGE_INTEGER cur_time;
|
||||
cur_time.HighPart = cur_ftime.dwHighDateTime;
|
||||
cur_time.LowPart = cur_ftime.dwLowDateTime;
|
||||
|
||||
const double ticksPerSecond = 10000000.0;
|
||||
auto timeInSeconds = (double)(cur_time.QuadPart - start_time.QuadPart) / ticksPerSecond;
|
||||
|
||||
return int(timeInSeconds * 1000.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
double getAccurateTime() const {
|
||||
#ifndef WIN_MODE
|
||||
timeval cur_time;
|
||||
gettimeofday(&cur_time, 0);
|
||||
|
||||
return (double)(cur_time.tv_sec - start_time.tv_sec)
|
||||
+ (double)(cur_time.tv_usec - start_time.tv_usec)/1000000.0;
|
||||
#else
|
||||
LARGE_INTEGER cur_time, cur_freq;
|
||||
QueryPerformanceCounter(&cur_time);
|
||||
QueryPerformanceFrequency(&cur_freq);
|
||||
|
||||
return (double)cur_time.QuadPart / (double)cur_freq.QuadPart - (double)start_time_hq.QuadPart / (double)start_time_hq_freq.QuadPart;
|
||||
#endif
|
||||
}
|
||||
|
||||
void resetGameTime(double time) {
|
||||
//Game time starts slightly ahead of render time
|
||||
gameTime = time;
|
||||
gameSpeed = 1;
|
||||
}
|
||||
|
||||
double getGameTime() const {
|
||||
return gameTime;
|
||||
}
|
||||
|
||||
double getFrameTime() const {
|
||||
return frameTime;
|
||||
}
|
||||
|
||||
double getGameSpeed() const {
|
||||
return gameSpeed;
|
||||
}
|
||||
|
||||
void setGameSpeed(double speed) {
|
||||
gameSpeed = speed;
|
||||
}
|
||||
|
||||
unsigned getProcessorCount() {
|
||||
return std::max(threads::getNumberOfProcessors(),1u);
|
||||
}
|
||||
|
||||
void setWindowTitle(const char* str) {
|
||||
glfwSetWindowTitle(window, str);
|
||||
}
|
||||
|
||||
void setWindowSize(int width, int height){
|
||||
glfwSetWindowSize(window, width, height);
|
||||
}
|
||||
|
||||
void closeWindow() {
|
||||
glfwDestroyWindow(window);
|
||||
}
|
||||
};
|
||||
|
||||
void redirectWindowClose(GLFWwindow*) {
|
||||
driver->onWindowClose();
|
||||
}
|
||||
|
||||
void redirectWindowResize(GLFWwindow*, int w, int h) {
|
||||
driver->onResize(w,h);
|
||||
driver->win_width = w;
|
||||
driver->win_height = h;
|
||||
glViewport(0, 0, w, h);
|
||||
}
|
||||
|
||||
void redirectSpecialKey(GLFWwindow*, int key, int scan, int action, int mods) {
|
||||
driver->shiftKey = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
driver->ctrlKey = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
driver->altKey = (mods & GLFW_MOD_ALT) != 0;
|
||||
|
||||
bool pressed;
|
||||
int keyaction;
|
||||
switch(action) {
|
||||
case GLFW_PRESS:
|
||||
pressed = true;
|
||||
keyaction = KA_Pressed;
|
||||
break;
|
||||
case GLFW_RELEASE:
|
||||
pressed = false;
|
||||
keyaction = KA_Released;
|
||||
break;
|
||||
case GLFW_REPEAT:
|
||||
pressed = true;
|
||||
keyaction = KA_Repeated;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
switch(key) {
|
||||
case GLFW_KEY_LEFT_SHIFT:
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
driver->shiftKey = pressed;
|
||||
break;
|
||||
|
||||
case GLFW_KEY_LEFT_CONTROL:
|
||||
case GLFW_KEY_RIGHT_CONTROL:
|
||||
driver->ctrlKey = pressed;
|
||||
break;
|
||||
|
||||
case GLFW_KEY_LEFT_ALT:
|
||||
case GLFW_KEY_RIGHT_ALT:
|
||||
driver->altKey = pressed;
|
||||
break;
|
||||
}
|
||||
|
||||
driver->onKeyEvent(key, keyaction);
|
||||
}
|
||||
|
||||
void redirectCharKey(GLFWwindow*, unsigned key) {
|
||||
driver->onCharTyped(key);
|
||||
}
|
||||
|
||||
void redirectMouseButton(GLFWwindow*, int button, int action, int mods) {
|
||||
bool pressed = action == GLFW_PRESS;
|
||||
|
||||
driver->shiftKey = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
driver->ctrlKey = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
driver->altKey = (mods & GLFW_MOD_ALT) != 0;
|
||||
|
||||
switch(button) {
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
driver->leftButton = pressed;
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
driver->rightButton = pressed;
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE:
|
||||
driver->middleButton = pressed;
|
||||
break;
|
||||
}
|
||||
|
||||
driver->onMouseButton(button, pressed);
|
||||
}
|
||||
|
||||
void redirectMouseMove(GLFWwindow*, double x, double y) {
|
||||
driver->onMouseMoved((int)x, (int)y);
|
||||
driver->mouse_x = (int)x;
|
||||
driver->mouse_y = (int)y;
|
||||
}
|
||||
|
||||
void redirectMouseWheel(GLFWwindow*, double x, double y) {
|
||||
driver->onScroll(x, y);
|
||||
}
|
||||
|
||||
void trackMouseOver(GLFWwindow*,int over) {
|
||||
driver->mouseOver = over == GL_TRUE;
|
||||
}
|
||||
|
||||
void glfwError(int code, const char* msg) {
|
||||
error("GLFW Error %d: %s", code, msg);
|
||||
}
|
||||
|
||||
OSDriver* getGLFWDriver() {
|
||||
if(!driver)
|
||||
driver = new GLFWDriver();
|
||||
return driver;
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user