move gl attributes to right before opening gl context; file to string func

This commit is contained in:
frank 2021-07-02 22:42:48 -04:00
parent 17adaed169
commit 569e203409
5 changed files with 229 additions and 147 deletions

View File

@ -41,8 +41,8 @@ void FramerateIndicator::refresh()
Game::Game()
{
// set the appropriate priority level for the default log category so either info level messages
// and higher are enabled or debug level messages are enabled, depending on the global configuration
/* Set the appropriate priority level for the default log category so either info level messages
* and higher are enabled or debug level messages are enabled, depending on the global configuration */
SDL_LogPriority default_log_category_priority;
if (get_configuration()["log"]["debug-to-file"] || get_configuration()["log"]["debug-to-stdout"])
{
@ -53,44 +53,43 @@ Game::Game()
default_log_category_priority = SDL_LOG_PRIORITY_INFO;
}
SDL_LogSetPriority(DEFAULT_SDL_LOG_CATEGORY, default_log_category_priority);
// set custom log function (prints to stdout/stderr and to file if enabled)
/* set custom log function that prints to stdout/stderr and to file if enabled */
SDL_LogSetOutputFunction(&Game::sdl_log_override, this);
// pretty print config to debug log
std::stringstream config_formatted;
config_formatted << std::setw(4) << get_configuration() << std::endl;
SDL_LogDebug(DEFAULT_SDL_LOG_CATEGORY, "%s", config_formatted.str().c_str());
/* pretty print config to debug log */
std::ostringstream log_message;
log_message << std::setw(4) << get_configuration() << std::endl;
debug(log_message.str());
/* tell SDL which render driver you will be requesting when calling SDL_CreateRenderer */
SDL_SetHint(SDL_HINT_RENDER_DRIVER, get_configuration()["display"]["render driver"].get<std::string>().c_str());
/* initialize the buffer of frame lengths which will be used to calculate FPS */
frame_length_history.reserve(5000);
set_framerate(get_configuration()["display"]["framerate"]);
delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT);
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0");
// putenv("SDL_VIDEO_CENTERED=0");
/* Needed for displaying fullscreen correctly on Linux (?) Also might need SDL_VIDEO_CENTERED (?) */
std::string fullscreen_env_assigment = "SDL_VIDEO_X11_LEGACY_FULLSCREEN=0";
putenv(const_cast<char*>(fullscreen_env_assigment.c_str()));
/* log compiled and linked SDL versions */
SDL_version version;
log_message = std::ostringstream();
SDL_VERSION(&version);
log_message << "compiled against SDL " << static_cast<int>(version.major) << "." << static_cast<int>(version.minor) <<
"." << static_cast<int>(version.patch) << std::endl;
SDL_GetVersion(&version);
SDL_Log("SDL %d.%d.%d", version.major, version.minor, version.patch);
fprintf(stderr, "stderr test message\n");
log_message << "linked to SDL " << static_cast<int>(version.major) << "." << static_cast<int>(version.minor) << "." <<
static_cast<int>(version.patch);
log(log_message.str());
/* allows use of our own main function (?) see SDL_SetMainReady.html */
SDL_SetMainReady();
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
// print_gl_attributes();
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
print_sdl_error("SDL could not initialize");
flag_to_end();
}
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
SDL_Log("GLEW %s", glewGetString(GLEW_VERSION));
auto window_size = get_configuration()["display"]["dimensions"].get<glm::ivec2>();
log_message = std::ostringstream();
log_message << "GLEW " << glewGetString(GLEW_VERSION);
log(log_message.str());
glm::ivec2 window_size = get_configuration()["display"]["dimensions"].get<glm::ivec2>();
/* Create a window with dimensions set in the config, centered, and flagged to be usable in OpenGL context */
window = SDL_CreateWindow(
get_configuration()["display"]["title"].get_ref<const std::string&>().c_str(), SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, window_size.x, window_size.y, SDL_WINDOW_OPENGL);
@ -99,6 +98,9 @@ Game::Game()
print_sdl_error("Could not create window");
flag_to_end();
}
/* Create an SDL renderer for clearing the screen to black and for logging renderer properties. Destroy renderer
* when finished.
*/
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr)
{
print_sdl_error("Could not create renderer");
@ -107,8 +109,12 @@ Game::Game()
else
{
int w, h;
/* log the renderer resolution */
SDL_GetRendererOutputSize(renderer, &w, &h);
SDL_Log("renderer output size is (%i, %i)", w, h);
log_message = std::ostringstream();
log_message << "renderer output size is " << w << "x" << h;
log(log_message.str());
/* clear screen to black */
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
@ -151,22 +157,89 @@ Game::Game()
const int audio_device_count = SDL_GetNumAudioDevices(SDL_TRUE);
for (int ii = 0; ii < audio_device_count; ii++)
{
SDL_Log("Found audio capture device %i: %s", ii,
SDL_GetAudioDeviceName(ii, SDL_TRUE));
SDL_Log("Found audio capture device %i: %s", ii, SDL_GetAudioDeviceName(ii, SDL_TRUE));
}
audio.load_sfx();
audio.load_bgm();
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
SDL_Log("big endian");
log("big endian");
#else
SDL_Log("little endian");
log("little endian");
#endif
last_frame_timestamp = SDL_GetTicks();
}
Game::~Game()
void Game::load_sdl_context()
{
get_delegate().unsubscribe(this);
if (glcontext != nullptr)
{
SDL_GL_DeleteContext(glcontext);
glcontext = nullptr;
}
SDL_RendererInfo renderer_info;
int render_driver_count = SDL_GetNumRenderDrivers();
SDL_Log("Render drivers:");
for (int ii = 0; ii < render_driver_count; ii++)
{
SDL_GetRenderDriverInfo(ii, &renderer_info);
log_renderer_info(renderer_info);
}
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr)
{
print_sdl_error("Could not create renderer");
flag_to_end();
}
else
{
SDL_Log("Current renderer:");
SDL_GetRendererInfo(renderer, &renderer_info);
log_renderer_info(renderer_info);
SDL_Log("Renderer supports the use of render targets? %d", SDL_RenderTargetSupported(renderer));
}
is_gl_context = false;
log_display_mode();
}
void Game::load_gl_context()
{
if (renderer != nullptr)
{
SDL_DestroyRenderer(renderer);
renderer = nullptr;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
if ((glcontext = SDL_GL_CreateContext(window)) == nullptr)
{
print_sdl_error("Could not get GL context");
flag_to_end();
}
/* try enabling vsync */
if (SDL_GL_SetSwapInterval(1) == 0)
{
log("enabled vsync");
}
else
{
log("vsync not supported");
}
GLenum error = glewInit();
std::ostringstream message;
if (error != GLEW_OK)
{
message << "GLEW could not initialize " << glewGetErrorString(error);
print_error(message.str());
}
message << "OpenGL " << glGetString(GL_VERSION) << ", renderer " << glGetString(GL_RENDERER) << ", shading language " <<
glGetString(GL_SHADING_LANGUAGE_VERSION);
log(message.str());
is_gl_context = true;
log_display_mode();
}
/* Overrides SDL's default log function to log a message to stdout/stderr and, if log is enabled in the
@ -221,21 +294,6 @@ void Game::print_sdl_error(const std::string& message)
sfw::print_sdl_error(message);
}
void Game::print_gl_attributes()
{
int major, minor;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
SDL_Log("GL CONTEXT: %i, %i", major, minor);
int r, g, b, a, buf;
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);
SDL_GL_GetAttribute(SDL_GL_BUFFER_SIZE, &buf);
SDL_Log("GL PIXELS: red: %i green: %i blue: %i alpha: %i", r, g, b, a);
}
void Game::print_frame_length_history()
{
for (float& frame_length : frame_length_history)
@ -245,65 +303,62 @@ void Game::print_frame_length_history()
std::cout << std::endl;
}
void Game::load_sdl_context()
/* Create, compile and return the ID of a GL shader from the GLSL code at path */
GLuint Game::load_shader(const fs::path& path, GLenum type) const
{
if (glcontext != nullptr)
GLuint shader = glCreateShader(type);
std::fstream file = std::fstream(path);
std::ostringstream message;
std::string contents = sfw::file_to_string(path);
glShaderSource(shader, 1, reinterpret_cast<const GLchar**>(&contents), 0);
// glShaderSource(shader, 1, const_cast<const GLchar**>(&buf), 0);
glCompileShader(shader);
GLint is_compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled);
if (is_compiled == GL_TRUE)
{
SDL_GL_DeleteContext(glcontext);
glcontext = nullptr;
}
SDL_RendererInfo renderer_info;
int render_driver_count = SDL_GetNumRenderDrivers();
SDL_Log("Render drivers:");
for (int ii = 0; ii < render_driver_count; ii++)
{
SDL_GetRenderDriverInfo(ii, &renderer_info);
log_renderer_info(renderer_info);
}
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr)
{
print_sdl_error("Could not create renderer");
flag_to_end();
message << "compiled shader at " << path;
log(message.str());
return shader;
}
else
{
SDL_Log("Current renderer:");
SDL_GetRendererInfo(renderer, &renderer_info);
log_renderer_info(renderer_info);
SDL_Log("Renderer supports the use of render targets? %d", SDL_RenderTargetSupported(renderer));
/* log error by allocating a string to copy the GL error message buffer into */
std::string error_info;
GLint max_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
error_info.resize(max_length, 0);
glGetShaderInfoLog(shader, error_info.size(), nullptr, error_info.data());
message << "failed to compile " << path << ": " << error_info;
log(message.str());
return -1;
}
is_gl_context = false;
log_display_mode();
}
void Game::load_gl_context()
bool Game::link_shader(GLuint program) const
{
if (renderer != nullptr)
glLinkProgram(program);
int is_linked;
glGetProgramiv(program, GL_LINK_STATUS, (int *) &is_linked);
std::ostringstream message;
if (is_linked == GL_TRUE)
{
SDL_DestroyRenderer(renderer);
renderer = NULL;
message << "linked shader program " << program;
log(message.str());
return true;
}
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
print_gl_attributes();
if ((glcontext = SDL_GL_CreateContext(window)) == NULL)
else
{
print_sdl_error("Could not get GL context");
flag_to_end();
/* log error by allocating a string to copy the GL error message buffer into */
std::string error_info;
GLint max_length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
error_info.resize(max_length, 0);
glGetProgramInfoLog(program, error_info.size(), nullptr, error_info.data());
message << "failed linking shader program " << program << ": " << error_info;
log(message.str());
return false;
}
GLenum error = glewInit();
if (error != GLEW_OK)
{
std::ostringstream message;
message << "GLEW could not initialize " << glewGetErrorString(error);
print_error(message.str());
}
SDL_Log("OpenGL %s, renderer %s, shading language %s",
glGetString(GL_VERSION), glGetString(GL_RENDERER),
glGetString(GL_SHADING_LANGUAGE_VERSION));
is_gl_context = true;
log_display_mode();
}
/* Send an info priority message to SDL's log output function, which is overridden by our own member
@ -338,76 +393,65 @@ bool Game::log_gl_errors(std::string suffix)
while ((error = glGetError()) != GL_NO_ERROR)
{
error_logged = true;
std::ostringstream message;
if (error == GL_INVALID_ENUM)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_ENUM, an unacceptable value is specified for an "
"enumerated argument %s", suffix.c_str());
message << "GL_INVALID_ENUM, an unacceptable value is specified for an enumerated argument";
}
else if (error == GL_INVALID_VALUE)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_VALUE, a numeric argument is out of range %s", suffix.c_str());
message << "GL_INVALID_VALUE, a numeric argument is out of range";
}
else if (error == GL_INVALID_OPERATION)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_OPERATION, the specified operation is not allowed "
"in the current state %s", suffix.c_str());
message << "GL_INVALID_OPERATION, the specified operation is not allowed in the current state";
}
else if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_FRAMEBUFFER_OPERATION, the framebuffer object is "
"not complete %s", suffix.c_str());
message << "GL_INVALID_FRAMEBUFFER_OPERATION, the framebuffer object is not complete";
}
else if (error == GL_OUT_OF_MEMORY)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_OUT_OF_MEMORY, there is not enough memory left to execute "
"the command %s", suffix.c_str());
message << "GL_OUT_OF_MEMORY, there is not enough memory left to execute the command";
}
else if (error == GL_STACK_UNDERFLOW)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_STACK_UNDERFLOW, an attempt has been made to perform an "
"operation that would cause an internal stack to underflow. %s", suffix.c_str());
message << "GL_STACK_UNDERFLOW, an attempt has been made to perform an operation that would " <<
"cause an internal stack to underflow";
}
else if (error == GL_STACK_OVERFLOW)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_STACK_OVERFLOW, an attempt has been made to perform an "
"operation that would cause an internal stack to overflow. %s", suffix.c_str());
message << "GL_STACK_OVERFLOW, an attempt has been made to perform an operation that would " <<
"cause an internal stack to overflow";
}
if (!suffix.empty())
{
message << " " << suffix;
}
log(message.str());
}
return error_logged;
}
// from SDL_GetCurrentDisplayMode.html
/* Write resolution, monitor refresh rate, and pixel format to the log. Code taken from SDL_GetCurrentDisplayMode.html
* on the SDL wiki */
void Game::log_display_mode()
{
SDL_DisplayMode current;
std::ostringstream message;
for (int ii = 0; ii < SDL_GetNumVideoDisplays(); ii++)
{
int mode = SDL_GetCurrentDisplayMode(ii, &current);
if (mode != 0)
{
SDL_Log("Could not get display mode for video display #%d: %s", ii,
SDL_GetError());
message << "Could not get display mode for video display #" << ii << ": " << SDL_GetError();
}
else
{
SDL_Log("Display #%d: display mode is %dx%dpx @ %dhz %s", ii,
current.w, current.h, current.refresh_rate,
get_pixel_format_string(current.format).c_str());
message << "Display #" << ii << ": display mode is " << current.w << "x" << current.h << "px @ " <<
current.refresh_rate << "hz " << get_pixel_format_string(current.format);
}
log(message.str());
}
}
@ -716,3 +760,8 @@ void Game::quit()
Mix_Quit();
SDL_Quit();
}
Game::~Game()
{
get_delegate().unsubscribe(this);
}

View File

@ -7,6 +7,7 @@
#include <iostream>
#include <sstream>
#include <ctime>
#include <fstream>
#define SDL_MAIN_HANDLED
#include "SDL.h"
@ -29,9 +30,10 @@
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Recorder.hpp"
#include "extension.hpp"
#include "Sprite.hpp"
#include "Audio.hpp"
#include "filesystem.hpp"
#include "extension.hpp"
struct FramerateIndicator : Sprite
{
@ -59,8 +61,8 @@ public:
static const int DEFAULT_SDL_LOG_CATEGORY = SDL_LOG_CATEGORY_CUSTOM;
SDL_Window* window;
SDL_Renderer* renderer = NULL;
SDL_GLContext glcontext = NULL;
SDL_Renderer* renderer = nullptr;
SDL_GLContext glcontext = nullptr;
int frame_count_this_second = 0, framerate, ticks, last_frame_length;
float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, last_frame_timestamp,
last_frame_count_timestamp, emscripten_previous_time;
@ -76,18 +78,18 @@ public:
FramerateIndicator framerate_indicator = FramerateIndicator(this);
Game();
~Game();
virtual void reset() { activate(); }
void print_error(const std::string&);
void print_sdl_error(const std::string&);
void print_gl_attributes();
void print_frame_length_history();
void load_sdl_context();
void load_gl_context();
GLuint load_shader(const fs::path&, GLenum) const;
bool link_shader(GLuint program) const;
void log(const std::string&, const int = DEFAULT_SDL_LOG_CATEGORY) const;
void debug(const std::string&, const int = DEFAULT_SDL_LOG_CATEGORY) const;
void log_renderer_info(SDL_RendererInfo&);
bool log_gl_errors(std::string);
bool log_gl_errors(std::string = "");
void log_display_mode();
void log_surface_format(SDL_Surface*, std::string = "surface");
std::string get_pixel_format_string(Uint32);
@ -107,6 +109,7 @@ public:
void handle_quit_event(SDL_Event&);
void quit();
virtual std::string get_class_name() const { return "Game"; }
~Game();
template<typename T>
float weight(T amount)

View File

@ -323,25 +323,26 @@ void Recorder::finish_writing_video()
{
write_mp4();
}
std::cout << "Wrote video frames to " << current_video_directory.string() <<
std::endl;
std::cout << "Wrote video frames to " << current_video_directory.string() << std::endl;
writing_recording = false;
}
/* Launch a system command that calls ffmpeg to write an x264 encoded MP4 from the image frames written.
* This requires ffmpeg to be installed on the user's system. Might only work on Linux (?) */
void Recorder::write_mp4()
{
glm::ivec2 size = get_display().get_window_size();
std::stringstream mp4_command;
std::string pixel_format =
get_configuration()["recording"]["mp4-pixel-format"].get<std::string>();
std::ostringstream mp4_command;
std::string pixel_format = get_configuration()["recording"]["mp4-pixel-format"].get<std::string>();
fs::path images_match = current_video_directory / "%05d.png";
mp4_command << "ffmpeg -f s16le -ac 2 -ar 22050 -i " << current_audio_path.string() <<
" -f image2 -framerate " << (1000 / get_frame_length()) <<
" -i " << images_match.string() << " -s " << size.x << "x" << size.y <<
" -c:v libx264 -crf 17 -pix_fmt " << pixel_format << " " <<
current_video_directory.string() << ".mp4";
std::cout << mp4_command.str() << std::endl;
std::system(mp4_command.str().c_str());
std::string mp4_command_str = mp4_command.str();
std::cout << mp4_command_str << std::endl;
std::system(mp4_command_str.c_str());
}
void Recorder::write_audio(Uint8* stream, int len)

View File

@ -1,7 +1,3 @@
#include <cstdlib>
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
#include "Pixels.hpp"
#include "extension.hpp"
@ -571,6 +567,37 @@ fs::path sfw::get_next_file_name(
return path;
}
/* Read the file at path into a string and return the string */
std::string sfw::file_to_string(const fs::path& path)
{
std::fstream file;
file.open(path);
std::ostringstream message;
std::string m_str;
if (!file.is_open())
{
message << "failed to open " << path;
message.str();
SDL_Log("%s", m_str.c_str());
return "";
}
else
{
message << "opened file " << path;
m_str = message.str();
SDL_Log("%s", m_str.c_str());
file.seekg(0, std::ios::end);
size_t size = file.tellg();
std::string contents;
contents.resize(size + 1, '\0');
file.seekg(0, std::ios::beg);
file.read(contents.data(), size);
contents[size] = '\0';
SDL_LogDebug(SDL_LOG_CATEGORY_CUSTOM, "%s", contents.c_str());
return contents;
}
}
void sfw::print_error(const std::string& message)
{
std::cerr << message << std::endl;

View File

@ -10,6 +10,8 @@
#include <stdexcept>
#include <map>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include "SDL.h"
#include "SDL_image.h"
@ -60,8 +62,8 @@ namespace sfw
SDL_Texture* get_pixel_scaled_texture(SDL_Renderer*, SDL_Texture*, int = 1, int = scaler::scale2x);
SDL_Surface* get_surface_from_pixels(Pixels&);
std::vector<fs::path> glob(fs::path);
fs::path get_next_file_name(
fs::path, int = 0, std::string = "", std::string = "");
fs::path get_next_file_name(fs::path, int = 0, std::string = "", std::string = "");
std::string file_to_string(const fs::path&);
void print_error(const std::string&);
void print_sdl_error(const std::string&);