#pragma once uint16_t constexpr const_hash(const char* input) { return *input ? static_cast(*input) + 33 * const_hash(input + 1) : 5381; } bool point_in_rect(const glm::vec2& point, const glm::vec4& rect); glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b); glm::vec4 rect_union(glm::vec4 a, glm::vec4 b); bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b, const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt); glm::vec4 rand_color(); glm::vec3 convert_hsv2rgb(const glm::vec3 c); glm::vec3 convert_rgb2hsv(const glm::vec3 c); size_t curl_data_handler(void *contents, size_t size, size_t nmemb, void *userp); void check_OpenGLError(const char* stmt, const char* fname, int line); template struct cbuffer { T m_vec[N]; int m_capacity; int m_count; int m_index; cbuffer() { m_capacity = N; m_index = 0; m_count = 0; } void clear() { m_index = 0; m_count = 0; } T& head() { return m_index == 0 ? m_vec[m_count - 1] : m_vec[m_index - 1]; } void add(const T& v) { m_vec[m_index] = v; m_index = (m_index + 1) % m_capacity; m_count = m_count < m_capacity ? m_count + 1 : m_count; } int count() const { return m_count; } template T2 average() const { T2 tot{}; if (m_count == 0) return tot; for (int i = 0; i < m_count; i++) tot += m_vec[i]; return tot / (float)m_count; } }; NS_START template class BlockingQueue { std::deque q; std::condition_variable post_cv; std::condition_variable get_cv; mutable std::mutex mutex; public: volatile bool unlocked = false; BlockingQueue() = default; BlockingQueue(const BlockingQueue& other) = delete; BlockingQueue& operator=(const BlockingQueue& other) = delete; BlockingQueue(BlockingQueue&& other) : q(std::move(q)) { } BlockingQueue& operator=(BlockingQueue&& other) { q = std::move(q); return *this; } void Post(T&& pkt) { std::unique_lock lock(mutex); if (Max > 0) { post_cv.wait(lock, [&]() { return unlocked | (q.size() < Max); }); if (q.size() >= Max) return; } q.push_back(std::forward(pkt)); get_cv.notify_one(); } T Get() { static T emptyT{}; std::unique_lock lock(mutex); get_cv.wait(lock, [&]() { return unlocked | (q.size() > 0); }); if (q.empty()) return std::move(emptyT); T tmp = std::move(q.front()); q.pop_front(); if (Max > 0) post_cv.notify_all(); return std::move(tmp); } void UnlockGetters() { unlocked = true; get_cv.notify_all(); if (Max > 0) post_cv.notify_all(); } int Size() const { std::lock_guard lock(mutex); return (int)q.size(); } }; struct gl_state { GLboolean blend; GLboolean depth_test; GLboolean scissor_test; GLint vp[4]; GLfloat cc[4]; GLint tex[10]; GLint cube; GLint sampler[10]; GLint program; GLint fb; GLint active_tex; void save() { blend = glIsEnabled(GL_BLEND); depth_test = glIsEnabled(GL_DEPTH_TEST); scissor_test = glIsEnabled(GL_SCISSOR_TEST); glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glGetIntegerv(GL_CURRENT_PROGRAM, &program); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb); glGetIntegerv(GL_ACTIVE_TEXTURE, &active_tex); glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &cube); for (int i = 0; i < 10; ++i) { glActiveTexture(GL_TEXTURE0 + i); glGetIntegerv(GL_TEXTURE_BINDING_2D, tex + i); glGetIntegerv(GL_SAMPLER_BINDING, sampler + i); } } void restore() { blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND); depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST); glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); glBindFramebuffer(GL_FRAMEBUFFER, fb); glUseProgram(program); for (int i = 0; i < 10; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, tex[i]); glBindSampler(i, sampler[i]); } glActiveTexture(active_tex); glBindTexture(GL_TEXTURE_CUBE_MAP, cube); } }; NS_END