taisei/src/video.c

437 lines
11 KiB
C
Raw Normal View History

2012-07-28 22:53:53 +02:00
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <png.h>
2012-07-28 22:53:53 +02:00
#include "global.h"
#include "video.h"
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
#include "taiseigl.h"
2017-04-01 02:08:35 +02:00
Video video;
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
static bool libgl_loaded = false;
2012-07-28 22:53:53 +02:00
static VideoMode common_modes[] = {
{RESX, RESY},
2012-07-28 22:53:53 +02:00
{640, 480},
{800, 600},
{1024, 768},
{1280, 960},
{1152, 864},
{1400, 1050},
{1440, 1080},
2012-07-28 22:53:53 +02:00
{0, 0},
};
static void video_add_mode(int width, int height) {
if(video.modes) {
int i; for(i = 0; i < video.mcount; ++i) {
VideoMode *m = &(video.modes[i]);
if(m->width == width && m->height == height)
return;
}
}
2012-07-28 22:53:53 +02:00
video.modes = (VideoMode*)realloc(video.modes, (++video.mcount) * sizeof(VideoMode));
video.modes[video.mcount-1].width = width;
video.modes[video.mcount-1].height = height;
}
static int video_compare_modes(const void *a, const void *b) {
VideoMode *va = (VideoMode*)a;
VideoMode *vb = (VideoMode*)b;
return va->width * va->height - vb->width * vb->height;
}
void video_get_viewport_size(int *width, int *height) {
float w = video.current.width;
float h = video.current.height;
float r = w / h;
if(r > VIDEO_ASPECT_RATIO) {
w = h * VIDEO_ASPECT_RATIO;
} else if(r < VIDEO_ASPECT_RATIO) {
h = w / VIDEO_ASPECT_RATIO;
}
*width = w;
*height = h;
}
void video_set_viewport(void) {
int w, h;
video_get_viewport_size(&w,&h);
glClear(GL_COLOR_BUFFER_BIT);
glViewport((video.current.width - w) / 2, (video.current.height - h) / 2, w, h);
}
void video_update_vsync(void) {
if(global.frameskip || config_get_int(CONFIG_VSYNC) == 1) {
SDL_GL_SetSwapInterval(0);
} else {
switch (config_get_int(CONFIG_VSYNC)) {
case 2: // adaptive
if(SDL_GL_SetSwapInterval(-1) < 0) {
case 0: // on
if(SDL_GL_SetSwapInterval(1) < 0) {
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_warn("SDL_GL_SetSwapInterval() failed: %s", SDL_GetError());
}
}
break;
}
}
}
2017-03-05 03:22:41 +01:00
#ifdef DEBUG_GL
static void APIENTRY video_gl_debug(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const void *arg
) {
char *strtype = "unknown";
char *strsev = "unknown";
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
LogLevel lvl = LOG_DEBUG;
2017-03-05 03:22:41 +01:00
switch(type) {
2017-03-13 17:03:51 +01:00
case GL_DEBUG_TYPE_ERROR: strtype = "error"; lvl = LOG_FATAL; break;
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strtype = "deprecated"; lvl = LOG_WARN; break;
2017-03-05 03:22:41 +01:00
case GL_DEBUG_TYPE_PORTABILITY: strtype = "portability"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strtype = "undefined"; break;
case GL_DEBUG_TYPE_PERFORMANCE: strtype = "performance"; break;
case GL_DEBUG_TYPE_OTHER: strtype = "other"; break;
}
switch(severity) {
case GL_DEBUG_SEVERITY_LOW: strsev = "low"; break;
case GL_DEBUG_SEVERITY_MEDIUM: strsev = "medium"; break;
case GL_DEBUG_SEVERITY_HIGH: strsev = "high"; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: strsev = "notify"; break;
}
if(type == GL_DEBUG_TYPE_OTHER && severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
// too verbose, spits a message every time some text is drawn
return;
2017-03-05 03:22:41 +01:00
}
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_custom(lvl, "[OpenGL debug, %s, %s] %i: %s", strtype, strsev, id, message);
2017-03-05 03:22:41 +01:00
}
static void APIENTRY video_gl_debug_enable(void) {
GLuint unused = 0;
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(video_gl_debug, NULL);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, true);
log_info("Enabled OpenGL debugging");
2017-03-05 03:22:41 +01:00
}
#endif
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
static void video_init_gl(void) {
video.glcontext = SDL_GL_CreateContext(video.window);
load_gl_functions();
check_gl_extensions();
2017-03-05 03:22:41 +01:00
#ifdef DEBUG_GL
if(glext.debug_output) {
2017-03-05 03:22:41 +01:00
video_gl_debug_enable();
} else {
log_warn("OpenGL debugging is not supported by the implementation");
2017-03-05 03:22:41 +01:00
}
#endif
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
init_quadvbo();
glClear(GL_COLOR_BUFFER_BIT);
}
static void video_update_quality(void) {
int vw, vh;
video_get_viewport_size(&vw,&vh);
float q = (float)vh / SCREEN_H;
float fg = q * config_get_float(CONFIG_FG_QUALITY);
float bg = q * config_get_float(CONFIG_BG_QUALITY);
float text = q * config_get_float(CONFIG_TEXT_QUALITY);
log_debug("q:%f, fg:%f, bg:%f, text:%f", q, fg, bg, text);
reinit_fbo(&resources.fbo.bg[0], bg);
reinit_fbo(&resources.fbo.bg[1], bg);
reinit_fbo(&resources.fbo.fg[0], fg);
reinit_fbo(&resources.fbo.fg[1], fg);
reload_fonts(text);
}
static void _video_setmode(int w, int h, uint32_t flags, bool fallback) {
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
if(!libgl_loaded) {
load_gl_library();
libgl_loaded = true;
}
2012-07-28 22:53:53 +02:00
if(!fallback) {
video.intended.width = w;
video.intended.height = h;
}
2017-02-04 03:56:40 +01:00
if(video.window) {
SDL_DestroyWindow(video.window);
video.window = NULL;
}
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
2017-03-05 03:22:41 +01:00
#ifdef DEBUG_GL
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
#endif
2017-02-04 03:56:40 +01:00
video.window = SDL_CreateWindow(WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags);
if(video.window) {
if(video.glcontext) {
SDL_GL_MakeCurrent(video.window, video.glcontext);
} else {
Refactored the gl loader into a polyglot macro monstrosity We no longer link to libGL by default. All GL functions are loaded dynamically through SDL apis. Use -DLINK_TO_LIBGL to enable linking, in which case Taisei won't try to dynamically load any of the gl functions. Previously we used a strange inconsistent setup where some functions were loaded dynamically and others pulled from the linked library. We also no longer link to libGLU even if LINK_TO_LIBGL is set. The only function we used from that library was gluPerspective. taiseigl now provides a simple substitute via glFrustum. The SDL2 gl headers are now used instead of the system ones, this should be more portable. The taiseigl.h header contains generated code partially based on content from those headers. It also doubles as a python3 script that actually generates that code and inserts it into itself. It scans the Taisei source tree for gl* calls and generates code only for the functions we use, and a few manually specified ones that are called indirectly. Assumptions such as "linux = glx" are no longer made. SDL takes care of platform specifics, as it should. The GL_EXT_draw_instanced/GL_ARB_draw_instanced extension detection has been improved. Taisei should be able to figure out which one to use without a compile-time check, and support for the ARB version has been actually implemented for the laser snippet loader. I've tested it on Windows 8 with Intel drivers that don't support the EXT version but do support the ARB one, instanced drawing works and the lasers don't lag! OSX should benefit from this change as well, although I've not yet tested the OSX build, beyond simply compiling it.
2017-02-24 01:54:28 +01:00
video_init_gl();
}
2017-02-04 03:56:40 +01:00
if(!video.glcontext) {
2017-03-13 17:03:51 +01:00
log_fatal("Error creating OpenGL context: %s", SDL_GetError());
2012-07-28 22:53:53 +02:00
return;
}
2017-02-04 03:56:40 +01:00
2017-02-27 17:38:35 +01:00
SDL_ShowCursor(false);
video_update_vsync();
SDL_GL_GetDrawableSize(video.window, &video.current.width, &video.current.height);
video.real.width = video.current.width;
video.real.height = video.current.height;
video_set_viewport();
video_update_quality();
2017-02-04 03:56:40 +01:00
return;
}
if(fallback) {
2017-03-13 17:03:51 +01:00
log_fatal("Error opening screen: %s", SDL_GetError());
2017-02-04 03:56:40 +01:00
return;
2012-07-28 22:53:53 +02:00
}
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_warn("Setting %dx%d (%s) failed, falling back to %dx%d (windowed)", w, h,
(flags & SDL_WINDOW_FULLSCREEN) ? "fullscreen" : "windowed", RESX, RESY);
_video_setmode(RESX, RESY, flags & ~SDL_WINDOW_FULLSCREEN, true);
2012-07-28 22:53:53 +02:00
}
void video_setmode(int w, int h, bool fs, bool resizable) {
if( w == video.current.width &&
h == video.current.height &&
fs == video_isfullscreen() &&
resizable == video_isresizable()
) return;
uint32_t flags = SDL_WINDOW_OPENGL;
if(fs) {
flags |= SDL_WINDOW_FULLSCREEN;
} else if(flags & SDL_WINDOW_RESIZABLE) {
flags |= SDL_WINDOW_RESIZABLE;
}
_video_setmode(w, h, flags, false);
log_info("Changed mode to %ix%i%s%s",
video.current.width,
video.current.height,
video_isfullscreen() ? ", fullscreen" : ", windowed",
video_isresizable() ? ", resizable" : ""
);
2012-07-28 22:53:53 +02:00
}
void video_take_screenshot(void) {
2017-03-12 21:54:34 +01:00
SDL_RWops *out;
char *data;
char outfile[128], *outpath;
time_t rawtime;
struct tm * timeinfo;
int w, h, rw, rh;
w = video.current.width;
h = video.current.height;
rw = video.real.width;
rh = video.real.height;
2017-03-25 19:59:36 +01:00
rw = max(rw, w);
rh = max(rh, h);
data = malloc(3 * rw * rh);
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(outfile, 128, "/taisei_%Y%m%d_%H-%M-%S_%Z.png", timeinfo);
outpath = strjoin(get_screenshots_path(), outfile, NULL);
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_info("Saving screenshot as %s", outpath);
2017-03-12 21:54:34 +01:00
out = SDL_RWFromFile(outpath, "w");
free(outpath);
if(!out) {
2017-03-25 19:59:36 +01:00
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
free(data);
return;
}
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, rw, rh, GL_RGB, GL_UNSIGNED_BYTE, data);
png_structp png_ptr;
png_infop info_ptr;
png_byte **row_pointers;
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_setup_error_handlers(png_ptr);
info_ptr = png_create_info_struct(png_ptr);
png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
row_pointers = png_malloc(png_ptr, h*sizeof(png_byte *));
for(int y = 0; y < h; y++) {
row_pointers[y] = png_malloc(png_ptr, 8*3*w);
memcpy(row_pointers[y], data + rw*3*(h-1-y), w*3);
}
png_init_rwops_write(png_ptr, out);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for(int y = 0; y < h; y++)
png_free(png_ptr, row_pointers[y]);
png_free(png_ptr, row_pointers);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(data);
2017-03-12 21:54:34 +01:00
SDL_RWclose(out);
}
bool video_isresizable(void) {
return SDL_GetWindowFlags(video.window) & SDL_WINDOW_RESIZABLE;
}
bool video_isfullscreen(void) {
return SDL_GetWindowFlags(video.window) & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP);
2012-07-28 22:53:53 +02:00
}
void video_set_fullscreen(bool fullscreen) {
video_setmode(video.intended.width, video.intended.height, fullscreen, video_isresizable());
}
2012-07-28 22:53:53 +02:00
void video_toggle_fullscreen(void) {
video_set_fullscreen(!video_isfullscreen());
2012-07-28 22:53:53 +02:00
}
void video_resize(int w, int h) {
video.current.width = w;
video.current.height = h;
video_set_viewport();
video_update_quality();
}
static void video_cfg_fullscreen_callback(ConfigIndex idx, ConfigValue v) {
2017-03-01 01:40:50 +01:00
video.intended.width = config_get_int(CONFIG_VID_WIDTH);
video.intended.height = config_get_int(CONFIG_VID_HEIGHT);
video_set_fullscreen(config_set_int(idx, v.i));
}
static void video_cfg_vsync_callback(ConfigIndex idx, ConfigValue v) {
config_set_int(idx, v.i);
video_update_vsync();
}
static void video_cfg_resizable_callback(ConfigIndex idx, ConfigValue v) {
SDL_SetWindowResizable(video.window, config_set_int(idx, v.i));
}
static void video_quality_callback(ConfigIndex idx, ConfigValue v) {
config_set_float(idx, v.f);
video_update_quality();
}
2012-07-28 22:53:53 +02:00
void video_init(void) {
int i, s;
bool fullscreen_available = false;
2017-02-04 03:56:40 +01:00
2012-07-28 22:53:53 +02:00
memset(&video, 0, sizeof(video));
memset(&resources.fbo, 0, sizeof(resources.fbo));
2017-02-04 03:56:40 +01:00
// First, register all resolutions that are available in fullscreen
2017-02-04 03:56:40 +01:00
for(s = 0; s < SDL_GetNumVideoDisplays(); ++s) {
for(i = 0; i < SDL_GetNumDisplayModes(s); ++i) {
SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
2017-02-04 03:56:40 +01:00
if(SDL_GetDisplayMode(s, i, &mode) != 0) {
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_warn("SDL_GetDisplayMode() failed: %s", SDL_GetError());
2017-02-04 03:56:40 +01:00
} else {
video_add_mode(mode.w, mode.h);
fullscreen_available = true;
2017-02-04 03:56:40 +01:00
}
}
}
if(!fullscreen_available) {
Implemented a simple and consistent logging subsystem The goal of this change is mainly to clean up Taisei's codebase and improve its console output. I've been frustrated by files littered with inconsistent printf/fprintf/warnx/errx calls for a long time, and now I actually did something about it. All the above functions are now considered deprecated and result in a compile-time warning when used. Instead, the following macros should be used: log_debug(format, ...) log_info(format, ...) log_warn(format, ...) log_err(format, ...) As you can see, all of them have the same printf-like interface. But they have different functionality and purpose: log_debug is intended for very verbose and specific information. It does nothing in release builds, much like assert(), so don't use expressions with side-effects in its arguments. log_info is for various status updates that are expected during normal operation of the program. log_warn is for non-critical failures or other things that may be worth investigating, but don't inherently render the program non-functional. log_err is for when the only choice is to give up. Like errx, it also terminates the program. Unlike errx, it actually calls abort(), which means the cleanup functions are not ran -- but on the other hand, you get a debuggable backtrace. However, if you're trying to catch programming errors, consider using assert() instead. All of them produce output that contains a timestamp, the log level identifier, the calling function's name, and the formatted message. The newline at the end of the format string is not required -- no, it is actually *prohibited*. The logging system will take care of the line breaks by itself, don't litter the code with that shit. Internally, the logging system is based on the SDL_RWops abstraction, and may have multiple, configurable destinations. This makes it easily extensible. Currently, log_debug and log_info are set to write to stdout, log_warn and log_err to stderr, and all of them also to the file log.txt in the Taisei config directory. Consequently, the nasty freopen hacks we used to make Taisei write to log files on Windows are no longer needed -- which is a very good thing, considering they probably would break if the configdir path contains UTF-8 characters. SDL_RWFromFile does not suffer this limitation. As an added bonus, it's also thread-safe. Note about printf and fprintf: in very few cases, the logging system is not a good substitute for these functions. That is, when you care about writing exactly to stdout/stderr and about exactly how the output looks. However, I insist on keeping the deprecation warnings on them to not tempt anyone to use them for logging/debugging out of habit and/or laziness. For this reason, I've added a tsfprintf function to util.c. It is functionally identical to fprintf, except it returns void. Yes, the name is deliberately ugly. Avoid using it if possible, but if you must, only use it to write to stdout or stderr. Do not write to actual files with it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
log_warn("No available fullscreen modes");
2017-02-17 17:03:49 +01:00
config_set_int(CONFIG_FULLSCREEN, false);
2012-07-28 22:53:53 +02:00
}
2017-02-04 03:56:40 +01:00
2012-07-28 22:53:53 +02:00
// Then, add some common 4:3 modes for the windowed mode if they are not there yet.
// This is required for some multihead setups.
for(i = 0; common_modes[i].width; ++i)
video_add_mode(common_modes[i].width, common_modes[i].height);
2012-07-28 22:53:53 +02:00
// sort it, mainly for the options menu
qsort(video.modes, video.mcount, sizeof(VideoMode), video_compare_modes);
video_setmode(
config_get_int(CONFIG_VID_WIDTH),
config_get_int(CONFIG_VID_HEIGHT),
config_get_int(CONFIG_FULLSCREEN),
config_get_int(CONFIG_VID_RESIZABLE)
);
config_set_callback(CONFIG_FULLSCREEN, video_cfg_fullscreen_callback);
config_set_callback(CONFIG_VSYNC, video_cfg_vsync_callback);
config_set_callback(CONFIG_VID_RESIZABLE, video_cfg_resizable_callback);
config_set_callback(CONFIG_FG_QUALITY, video_quality_callback);
config_set_callback(CONFIG_BG_QUALITY, video_quality_callback);
config_set_callback(CONFIG_TEXT_QUALITY, video_quality_callback);
log_info("Video subsystem initialized");
2012-07-28 22:53:53 +02:00
}
void video_shutdown(void) {
2017-02-04 03:56:40 +01:00
SDL_DestroyWindow(video.window);
SDL_GL_DeleteContext(video.glcontext);
unload_gl_library();
2012-07-28 22:53:53 +02:00
free(video.modes);
}