30 #ifdef E3D_TARGET_WINDOWS
31 # ifndef WINSOCK2_IMPORTED
32 # define WINSOCK2_IMPORTED
33 # include <winsock2.h>
37 #ifdef E3D_TARGET_UNIX
41 #ifdef E3D_TARGET_SWITCH
45 #ifdef E3D_BACKEND_OPENGL
49 # include <GL/glext.h>
52 #elif defined E3D_BACKEND_GLES
53 # include <GLES3/gl3.h>
56 #include <SDL_events.h>
57 #include <SDL_keycode.h>
58 #include <SDL_mouse.h>
59 #include <SDL_audio.h>
60 #include <SDL_joystick.h>
62 #include "eng3d/state.hpp"
63 #include "eng3d/io.hpp"
64 #include "eng3d/audio.hpp"
65 #include "eng3d/texture.hpp"
66 #include "eng3d/material.hpp"
67 #include "eng3d/model.hpp"
68 #include "eng3d/log.hpp"
69 #include "eng3d/shader.hpp"
70 #include "eng3d/utils.hpp"
77 int setenv(
const char* name,
const char* value,
int overwrite)
82 errcode = getenv_s(&envsize, NULL, 0, name);
83 if(errcode || envsize)
return errcode;
85 return _putenv_s(name, value);
88 #if defined E3D_BACKEND_OPENGL
90 static void GLAPIENTRY GLDebugMessageCallback(GLenum source, GLenum type, GLuint
id, GLenum severity, GLsizei,
const GLchar* msg,
const void*) {
93 case GL_DEBUG_SOURCE_API:
96 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
97 _source =
"WINDOW SYSTEM";
99 case GL_DEBUG_SOURCE_SHADER_COMPILER:
100 _source =
"SHADER COMPILER";
102 case GL_DEBUG_SOURCE_THIRD_PARTY:
103 _source =
"THIRD PARTY";
105 case GL_DEBUG_SOURCE_APPLICATION:
106 _source =
"APPLICATION";
108 case GL_DEBUG_SOURCE_OTHER:
118 case GL_DEBUG_TYPE_ERROR:
121 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
122 _type =
"DEPRECATED BEHAVIOR";
124 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
125 _type =
"UDEFINED BEHAVIOR";
127 case GL_DEBUG_TYPE_PORTABILITY:
128 _type =
"PORTABILITY";
130 case GL_DEBUG_TYPE_PERFORMANCE:
131 _type =
"PERFORMANCE";
133 case GL_DEBUG_TYPE_OTHER:
136 case GL_DEBUG_TYPE_MARKER:
144 std::string _severity;
146 case GL_DEBUG_SEVERITY_HIGH:
149 case GL_DEBUG_SEVERITY_MEDIUM:
150 _severity =
"MEDIUM";
152 case GL_DEBUG_SEVERITY_LOW:
155 case GL_DEBUG_SEVERITY_NOTIFICATION:
156 _severity =
"NOTIFICATION";
159 _severity =
"UNKNOWN";
163 std::unique_ptr<char[]> tmpbuf(
new char[512]);
164 snprintf(tmpbuf.get(), 512,
"%d: %s of %s severity, raised from %s: %s",
id, _type.c_str(), _severity.c_str(), _source.c_str(), msg);
166 if(std::strchr(tmpbuf.get(),
'\n') ==
nullptr) {
181 if(g_state !=
nullptr)
182 CXX_THROW(std::runtime_error,
"Duplicate instancing of GameState");
185 #ifdef E3D_TARGET_UNIX
190 #ifdef E3D_TARGET_SWITCH
191 ::consoleDebugInit(debugDevice_SVC);
198 const int seed = (int)((uint32_t)time(NULL) * (uint32_t)getpid());
202 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
204 setenv(
"MESA_GL_VERSION_OVERRIDE",
"4.6", 0);
205 setenv(
"MESA_GLSL_VERSION_OVERRIDE",
"440", 0);
210 struct sigaction sa{};
211 sa.sa_restorer = []() ->
void {
214 sigaction(SIGPIPE, &sa, NULL);
216 std::string canonical_name =
translate(
"Symphony of Empires");
219 if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
221 SDL_ShowCursor(SDL_DISABLE);
222 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
223 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
224 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
227 #ifdef E3D_TARGET_SWITCH
235 #ifdef E3D_TARGET_SWITCH
236 s.
window = SDL_CreateWindow(canonical_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, s.width, s.height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE);
238 s.
window = SDL_CreateWindow(canonical_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, s.width, s.height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
244 s.context =
static_cast<void*
>(SDL_GL_CreateContext(s.
window));
245 if(s.context ==
nullptr)
247 SDL_GL_SetSwapInterval(1);
250 # ifdef E3D_BACKEND_OPENGL
251 glewExperimental = GL_TRUE;
258 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
261 # ifdef E3D_BACKEND_OPENGL
262 glHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
264 glEnable(GL_DEBUG_OUTPUT);
265 glDebugMessageCallback(GLDebugMessageCallback, 0);
269 # ifdef E3D_BACKEND_OPENGL
270 glEnable(GL_MULTISAMPLE);
271 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
272 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 1);
275 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
277 glEnable(GL_TEXTURE_2D);
278 # ifdef E3D_BACKEND_OPENGL
279 glEnableClientState(GL_VERTEX_ARRAY);
280 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
287 glEnable(GL_DEPTH_TEST);
288 glDepthMask(GL_TRUE);
289 glDepthFunc(GL_LEQUAL);
290 # ifdef E3D_BACKEND_OPENGL
291 glDepthRange(0.f, 1.f);
293 glDepthRangef(0.f, 1.f);
295 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
302 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
303 SDL_GL_DeleteContext(s.context);
305 SDL_DestroyWindow(s.window);
306 SDL_QuitSubSystem(SDL_INIT_VIDEO);
308 #ifdef E3D_TARGET_SWITCH
321 package_man(*this, pkg_paths),
331 for(
const auto& plugin : Path::get_all(
"plugin.dll")) {
332 #ifdef E3D_TARGET_WINDOWS
333 HINSTANCE hGetProcIDDLL = LoadLibrary(plugin.c_str());
340 typedef int(__stdcall* plugin_dll_entry_t)(
const char* gameid,
int gamever);
341 plugin_dll_entry_t entry = (plugin_dll_entry_t)GetProcAddress(hGetProcIDDLL,
"__unirend_entry");
347 int r = entry(
"SYMPHONY_EMPIRES", 0x00F0);
367 const auto read_file = [
this](
const std::string& file_name) {
368 return this->package_man.get_unique(
"shaders/" + file_name)->read_all();
370 const auto load_fragment_shader = [read_file](std::string file_name) {
371 return std::make_unique<Eng3D::OpenGL::FragmentShader>(read_file(file_name));
373 const auto load_vertex_shader = [read_file](std::string file_name) {
374 return std::make_unique<Eng3D::OpenGL::VertexShader>(read_file(file_name));
377 builtin_shaders.clear();
378 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
380 builtin_shaders[
"fs_lib"] = load_fragment_shader(
"lib.fs");
382 builtin_shaders[
"fs_2d"] = load_fragment_shader(
"2d.fs");
384 builtin_shaders[
"vs_2d"] = load_vertex_shader(
"2d.vs");
386 builtin_shaders[
"fs_3d"] = load_fragment_shader(
"3d.fs");
388 builtin_shaders[
"vs_3d"] = load_vertex_shader(
"3d.vs");
390 builtin_shaders[
"fs_tree"] = load_fragment_shader(
"tree.fs");
392 builtin_shaders[
"vs_tree"] = load_vertex_shader(
"tree.vs");
393 builtin_shaders[
"vs_font_sdf"] = load_vertex_shader(
"font_sdf.vs");
394 builtin_shaders[
"fs_font_sdf"] = load_fragment_shader(
"font_sdf.fs");
396 builtin_shaders[
"vs_piechart"] = load_vertex_shader(
"piechart.vs");
397 builtin_shaders[
"fs_piechart"] = load_fragment_shader(
"piechart.fs");
402 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
403 glClearColor(0, 0, 0, 1);
404 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
405 # ifdef E3D_BACKEND_OPENGL
414 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
416 glBindFramebuffer(GL_FRAMEBUFFER, 0);
417 SDL_GL_SwapWindow(window);
423 #include "eng3d/ui/ui.hpp"
424 #include "eng3d/ui/widget.hpp"
425 #include "eng3d/ui/window.hpp"
426 #include "eng3d/ui/text.hpp"
430 SDL_GetWindowSize(this->window, &this->width, &this->height);
431 this->ui_ctx.resize(this->width, this->height);
432 this->handle_resize();
435 while(SDL_PollEvent(&event)) {
437 case SDL_MOUSEBUTTONDOWN: {
440 e.type = e.from_sdl(event.button.button);
444 case SDL_MOUSEBUTTONUP: {
447 e.type = e.from_sdl(event.button.button);
451 case SDL_MOUSEMOTION: {
454 e.delta = this->mouse_pos - e.pos;
455 this->mouse_pos = e.pos;
456 handle_mouse_motion(e);
458 case SDL_MOUSEWHEEL: {
461 e.wheel.x =
event.wheel.x;
462 e.wheel.y =
event.wheel.y;
463 handle_mouse_wheel(e);
467 e.
type = e.from_sdl(event.key.keysym.sym);
473 e.
type = e.from_sdl(event.key.keysym.sym);
477 case SDL_TEXTINPUT: {
478 this->ui_ctx.check_text_input(event.text.text);
487 const std::scoped_lock lock(this->ui_ctx.prompt_queue_mutex);
488 for(
const auto& prompt : this->ui_ctx.prompt_queue) {
489 auto* win =
new UI::Window(-256, 0, 512, 512);
491 win->set_text(prompt.first);
492 win->is_scroll =
true;
493 win->set_close_btn_function([win](
UI::Widget&) {
496 auto& txt = win->make_widget<
UI::Text>(0, 0, win->width, win->height);
498 txt.set_text(prompt.second);
499 txt.is_scroll =
true;
500 win->height = txt.y + txt.height;
501 win->y -= win->height / 2;
503 this->ui_ctx.prompt_queue.clear();
504 this->ui_ctx.clear_dead();
508 #ifdef E3D_BACKEND_OPENGL
509 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
510 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
522 void Eng3D::State::do_run(std::function<
bool(
void)> cond, std::function<
void(
void)> event, std::function<
void(
void)> render) {
523 this->current_frame_time = std::chrono::system_clock::now();
525 auto prev_num = std::chrono::duration<double>(this->current_frame_time.time_since_epoch()).count();
526 auto now_num = std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch()).count();
527 this->current_frame_time = std::chrono::system_clock::now();
528 this->delta_time = now_num - prev_num;
532 if(this->show_ui) this->ui_ctx.render_all();
542 if(!this->show_ui)
return;
545 if(this->ui_ctx.check_click(e.
pos)) {
546 const std::scoped_lock lock(this->audio_man.sound_lock);
547 auto entries = this->package_man.get_multiple_prefix(
"sfx/click");
548 if(!entries.empty()) {
549 auto audio = this->audio_man.load(entries[rand() % entries.size()]->get_abs_path());
550 audio_man.sound_queue.push_back(audio);
556 this->ui_ctx.check_mouse_released(e.
pos);
562 this->ui_ctx.set_cursor_pos(e.
pos);
563 this->ui_ctx.check_drag(e.
pos);
564 this->ui_ctx.check_hover(e.
pos);
570 this->ui_ctx.check_hover(e.
pos);
571 if(this->ui_ctx.check_wheel(e.
pos, e.
wheel.y * 6))
return;
579 this->run = !this->run;
Installer(Eng3D::State &s)
void set_multisamples(int samples) const
State(const std::vector< std::string > &pkg_paths)
virtual void handle_key(const Eng3D::Event::Key &e)
virtual void handle_mouse_btn(const Eng3D::Event::MouseButton &e)
void do_run(std::function< bool(void)> cond, std::function< void(void)> event, std::function< void(void)> render)
Perform the main game loop.
static State & get_instance()
virtual void handle_mouse_motion(const Eng3D::Event::MouseMotion &e)
virtual void handle_mouse_wheel(const Eng3D::Event::MouseWheel &e)
virtual void handle_resize()
void resize(const int width, const int height)
Multiline textbox that allows more descriptive paragraphs than the Label widget.
Window widget, this widget is similar to a Group widget, the key difference is that this one can be m...
glm::ivec2 get_mouse_pos()
std::string translate(const std::string_view str)
void error(const std::string_view category, const std::string_view msg)
void debug(const std::string_view category, const std::string_view msg)
void warning(const std::string_view category, const std::string_view msg)
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Primitive color type used through the engine.
Eng3D::Event::Key::Type type
bool hold
Whetever the key is being held.
#define CXX_THROW(class,...)