#pragma once #ifdef _DEBUG #define GL(stmt) stmt; check_OpenGLError(#stmt, __FILE__, __LINE__); #else #define GL(stmt) stmt #endif struct vertex_t { glm::vec4 pos; glm::vec2 uvs; glm::vec2 uvs2; glm::vec3 nor; vertex_t() : pos(0), uvs(0), uvs2(0), nor(0) {} vertex_t(glm::vec2 p) : pos(p, 0, 1), uvs(0), uvs2(0), nor(0) {} vertex_t(glm::vec2 p, glm::vec2 uv) : pos(p, 0, 1), uvs(uv), uvs2(0), nor(0) {} vertex_t(glm::vec3 p) : pos(p, 1), uvs(0), uvs2(0), nor(0) {} vertex_t(glm::vec3 p, glm::vec2 uv) : pos(p, 1), uvs(uv), uvs2(0), nor(0) {} vertex_t(glm::vec4 p) : pos(p), uvs(0), uvs2(0), nor(0) {} vertex_t(glm::vec4 p, glm::vec2 uv) : pos(p), uvs(uv), uvs2(0), nor(0) {} vertex_t(glm::vec4 p, glm::vec2 uv, glm::vec2 uv2) : pos(p), uvs(uv), uvs2(uv2), nor(0) {} }; uint16_t constexpr const_hash(const char* input) { return *input ? static_cast(*input) + 33 * const_hash(input + 1) : 5381; } template std::vector poly_remove_duplicate(const std::vector& v, const float tollerance = 0.001) { std::vector ret; for (size_t i = 0; i < v.size(); i++) { //if (glm::distance2(v[i], v[(i + 1) % v.size()]) > tollerance) if (v[i] != v[(i + 1) % v.size()]) ret.push_back(v[i]); } return ret; } template<> std::vector poly_remove_duplicate(const std::vector& v, const float tollerance); // params {x, y} and {origin, size} form bool point_in_rect(const glm::vec2& point, const glm::vec4& rect); // params and returns {origin, size} form glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b); // params and returns {origin, size} form glm::vec4 rect_union(glm::vec4 a, glm::vec4 b); // params and returns {min, max} form glm::vec4 box_union(glm::vec4 a, glm::vec4 b); // params and returns {min, max} form glm::vec4 box_intersection(glm::vec4 a, glm::vec4 b); bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit, float& out_t); bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b, const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt, glm::vec2& out_hit_uv); bool point_side(glm::vec2 a, glm::vec2 b, glm::vec2 p); std::vector poly_intersect(const vertex_t* poly_begin, const vertex_t* poly_end, const std::vector& clip); std::vector poly_intersect(const std::vector& poly, const std::vector& clip); std::vector poly_clip_near(const std::vector& poly, float near_plane_distance); std::vector triangulate(const std::vector& points); std::vector triangulate(const std::vector& points); std::vector triangulate_simple(const std::vector& vertices); glm::vec4 rand_color(); glm::vec3 convert_hsv2rgb(const glm::vec3 c); glm::vec3 convert_rgb2hsv(const glm::vec3 c); std::vector split(const std::string& subject, char d, int max_split = 0); std::string unescape(const std::string& s); std::wstring str2wstr(const std::string& str); std::string wstr2str(const std::wstring& wstr); bool str_iequals(const std::string& a, const std::string& b); size_t curl_data_handler(void *contents, size_t size, size_t nmemb, void *userp); size_t curl_data_write(void *ptr, size_t size, size_t nmemb, FILE *stream); void check_OpenGLError(const char* stmt, const char* fname, int line); inline glm::vec2 xy(const glm::vec4& v) { return glm::vec2(v.x, v.y); } inline glm::vec3 xyz(const glm::vec4& v) { return glm::vec3(v.x, v.y, v.z); } inline glm::vec2 zw(const glm::vec4& v) { return glm::vec2(v.z, v.w); } inline glm::ivec2 xy(const glm::ivec4& v) { return glm::ivec2(v.x, v.y); } inline glm::ivec3 xyz(const glm::ivec4& v) { return glm::ivec3(v.x, v.y, v.z); } inline glm::ivec2 zw(const glm::ivec4& v) { return glm::ivec2(v.z, v.w); } inline glm::vec2 xy(const glm::vec3& v) { return glm::vec2(v.x, v.y); } void parallel_for(unsigned nb_elements, std::function functor, bool use_threads = true); template struct cbuffer { std::unique_ptr m_vec; int m_capacity = 0; int m_count = 0; int m_index = 0; cbuffer(int initial_capacity) { m_capacity = initial_capacity; m_index = 0; m_count = 0; m_vec = std::make_unique(m_capacity); } void resize(int new_capacity) { m_capacity = new_capacity; m_vec = std::make_unique(m_capacity); m_index = 0; m_count = 0; } void clear() { m_index = 0; m_count = 0; } const T& head() const { 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; } template T2 average_threshold(T threshold) const { T2 tot{}; if (m_count == 0) return tot; int n = 0; for (int i = 0; i < m_count; i++) tot += glm::abs(m_vec[i] - head()) < threshold ? 0 : m_vec[i], n++; return tot / (float)n; } }; 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; GLfloat line_width; 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); } };