8#include <glm/gtc/matrix_transform.hpp>
10#include <smk/Color.hpp>
11#include <smk/Drawable.hpp>
12#include <smk/Input.hpp>
13#include <smk/InputImpl.hpp>
14#include <smk/OpenGL.hpp>
15#include <smk/View.hpp>
16#include <smk/Window.hpp>
21 #include <emscripten.h>
22 #include <emscripten/html5.h>
27bool g_khr_parallel_shader =
false;
32std::map<int, Window*> window_by_id;
33std::map<GLFWwindow*, Window*> window_by_glfw_window;
35void GLFWScrollCallback(GLFWwindow* glfw_window,
38 Window* window = window_by_glfw_window[glfw_window];
43 dynamic_cast<InputImpl*
>(&(window->input()))
44 ->OnScrollEvent({xoffset, yoffset});
47void GLFWErrorCallback(
int error,
const char* description) {
48 std::cerr <<
"GFLW error n°" << error << std::endl;
49 std::cerr <<
"~~~" << std::endl;
50 std::cerr << description << std::endl;
51 std::cerr <<
"~~~" << std::endl;
52 fprintf(stderr,
"Error: %s\n", description);
57EM_BOOL OnTouchEvent(
int eventType,
58 const EmscriptenTouchEvent* keyEvent,
60 int g_next_id = (int)(userData);
61 Window* window = window_by_id[g_next_id];
65 static_cast<InputImpl*
>(&(window->input()))
66 ->OnTouchEvent(eventType, keyEvent);
70std::function<void(
void)> main_loop;
75EM_JS(
void, MakeCanvasSelectable, (
int window_id), {
80 if (!Module[
'canvas']) {
84 Module[
'canvas'].setAttribute(
"smk", window_id);
89#if !defined NDEBUG && !defined __EMSCRIPTEN__ && __linux__
90void OpenGLDebugMessageCallback(GLenum ,
95 const GLchar* message,
97 if (type == GL_DEBUG_TYPE_OTHER) {
100 std::cerr <<
"SMK > OpenGL error: " << std::string(message, length)
105void GLFWCharCallback(GLFWwindow* glfw_window,
unsigned int codepoint) {
106 Window* window = window_by_glfw_window[glfw_window];
110 dynamic_cast<InputImpl*
>(&(window->input()))
111 ->OnCharacterTyped((
wchar_t)codepoint);
119 window_by_id[id_] =
this;
127 input_ = std::make_unique<InputImpl>();
129 window_by_id[id_] =
this;
133 glfwSetErrorCallback(GLFWErrorCallback);
136 throw std::runtime_error(
"Couldn't init GLFW");
141 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
142 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
144 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
145 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
146 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
147 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
150 glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
151 glfwWindowHint(GLFW_SAMPLES, 4);
154 window_ = glfwCreateWindow(width_, height_, title.c_str(),
nullptr,
nullptr);
157 throw std::runtime_error(
"Couldn't create a window_");
159 window_by_glfw_window[window_] =
this;
161 glfwMakeContextCurrent(window_);
163#ifndef __EMSCRIPTEN__
164 glewExperimental = GL_TRUE;
165 GLenum err = glewInit();
167 if (err != GLEW_OK) {
169 std::string error = (
const char*)glewGetErrorString(err);
170 throw std::runtime_error(
"Could initialize GLEW, error = " + error);
174#if !defined NDEBUG && !defined __EMSCRIPTEN__ && __linux__
175 glEnable(GL_DEBUG_OUTPUT);
176 glDebugMessageCallback(OpenGLDebugMessageCallback, 0);
180 const GLubyte* renderer = glGetString(GL_RENDERER);
181 const GLubyte* version = glGetString(GL_VERSION);
182 std::cout <<
"Renderer: " << renderer << std::endl;
183 std::cout <<
"OpenGL version supported " << version << std::endl;
187 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
191#ifndef __EMSCRIPTEN__
192 if (GLEW_KHR_parallel_shader_compile) {
193 glMaxShaderCompilerThreadsKHR(4);
194 g_khr_parallel_shader =
true;
197 g_khr_parallel_shader = emscripten_webgl_enable_extension(
198 emscripten_webgl_get_current_context(),
"KHR_parallel_shader_compile");
200 MakeCanvasSelectable(id_);
202 module_canvas_selector_ =
"[smk='" + std::to_string(id_) +
"']";
204 emscripten_set_touchstart_callback(module_canvas_selector_.c_str(),
205 (
void*)id_,
true, OnTouchEvent);
206 emscripten_set_touchend_callback(module_canvas_selector_.c_str(), (
void*)id_,
208 emscripten_set_touchmove_callback(module_canvas_selector_.c_str(), (
void*)id_,
210 emscripten_set_touchcancel_callback(module_canvas_selector_.c_str(),
211 (
void*)id_,
true, OnTouchEvent);
213 glfwSetScrollCallback(window_, GLFWScrollCallback);
214 glfwSetCharCallback(window_, GLFWCharCallback);
218 operator=(std::move(window));
221Window& Window::operator=(Window&& other)
noexcept {
222 if (&other ==
this) {
225 std::swap(window_, other.window_);
226 std::swap(time_, other.time_);
227 std::swap(time_last_sleep_, other.time_last_sleep_);
228 std::swap(input_, other.input_);
229 std::swap(id_, other.id_);
230 std::swap(module_canvas_selector_, other.module_canvas_selector_);
232 window_by_id[id_] =
this;
233 window_by_glfw_window[window_] =
this;
240 input_->Update(window_);
246 glfwSwapBuffers(window_);
251 time_ =
static_cast<float>(glfwGetTime());
255 window_by_id.erase(id_);
271 return *(input_.get());
282 main_loop = [my_loop = loop] { (void)my_loop(); };
283 emscripten_set_main_loop(&MainLoop, 0, 1);
300 emscripten_set_main_loop(&MainLoop, 0, 1);
309void Window::UpdateDimensions() {
313 emscripten_get_canvas_element_size(module_canvas_selector_.c_str(), &width_,
316 glfwGetWindowSize(window_, &width_, &height_);
320 glViewport(0, 0, width_, height_);
328 const float delta =
static_cast<float>(glfwGetTime()) - time_last_sleep_;
329 const float target = 1.f / fps;
330 float sleep_duration = target - delta;
331 sleep_duration = std::min(target, sleep_duration);
332 if (sleep_duration > 0.f) {
333 std::this_thread::sleep_for(
334 std::chrono::microseconds(
int(sleep_duration * 1'000'000)));
336 time_last_sleep_ =
static_cast<float>(glfwGetTime());
341 return glfwWindowShouldClose(window_);
RenderTarget & operator=(RenderTarget &&other) noexcept
Move operator.
void SetView(const View &view)
Set the View to use.
int height() const
the height of the surface.
int width() const
the width of the surface.
A window. You can draw objects on the window.
void ExecuteMainLoop(const std::function< void(void)> &loop)
Helper function. Execute the main loop of the application. On web based application: registers the lo...
void PoolEvents()
Handle all the new input events. This update the input() object.
bool ShouldClose()
Returns true when the user wants to close the window.
void Display()
Present what has been draw to the screen.
void ExecuteMainLoopUntil(const std::function< bool(void)> &loop)
Helper function. Execute the main loop of the application. On web based application: registers the lo...
float time() const
The last time Window::PoolEvent() was called.
GLFWwindow * window() const
The window handle.
Input & input()
Return an object for querying the input state.
void LimitFrameRate(float fps)