Files
panopainter/src/util.h

277 lines
9.4 KiB
C++

#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<uint16_t>(*input) + 33 * const_hash(input + 1) :
5381;
}
template<class T>
std::vector<T> poly_remove_duplicate(const std::vector<T>& v, const float tollerance = 0.001)
{
std::vector<T> 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<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& 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<vertex_t> poly_intersect(const vertex_t* poly_begin, const vertex_t* poly_end, const std::vector<glm::vec2>& clip);
std::vector<glm::vec2> poly_intersect(const std::vector<glm::vec2>& poly, const std::vector<glm::vec2>& clip);
std::vector<glm::vec3> poly_clip_near(const std::vector<glm::vec3>& poly, float near_plane_distance);
std::vector<vertex_t> triangulate(const std::vector<vertex_t>& points);
std::vector<vertex_t> triangulate(const std::vector<glm::vec2>& points);
std::vector<vertex_t> triangulate_simple(const std::vector<vertex_t>& vertices);
glm::vec4 rand_color();
glm::vec3 convert_hsv2rgb(const glm::vec3 c);
glm::vec3 convert_rgb2hsv(const glm::vec3 c);
std::vector<std::string> 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);
std::string str_replace(const std::string& string, const std::string& search, const std::string& replace);
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(size_t nb_elements, std::function<void(size_t i)> functor, bool use_threads = true);
template<typename T> struct cbuffer
{
std::unique_ptr<T[]> 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<T[]>(m_capacity);
}
void resize(int new_capacity)
{
m_capacity = new_capacity;
m_vec = std::make_unique<T[]>(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<typename T2 = T> 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<typename T2 = T> 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<typename T, int Max = 0>
class BlockingQueue
{
public:
std::deque<std::pair<T, bool>> q;
std::condition_variable post_cv;
std::condition_variable get_cv;
mutable std::mutex mutex;
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<std::mutex> lock(mutex);
if (Max > 0)
{
post_cv.wait(lock, [&]() { return unlocked | (q.size() < Max); });
if (q.size() >= Max) return;
}
q.push_back({ pkt, false });
get_cv.notify_one();
}
void PostUnique(T pkt, bool top)
{
std::unique_lock<std::mutex> lock(mutex);
if (Max > 0)
{
post_cv.wait(lock, [&]() { return unlocked | (q.size() < Max); });
if (q.size() >= Max) return;
}
auto search = std::make_pair(pkt, top);
if (std::find(q.begin(), q.end(), search) == q.end())
{
if (top)
{
// find the first low priority
auto low = std::find_if(q.begin(), q.end(), [](auto const& x) { return x.second == false; });
q.insert(low, { pkt, top });
}
else
{
q.push_back({ pkt, top });
}
}
get_cv.notify_one();
}
T Get()
{
static T emptyT{};
std::unique_lock<std::mutex> lock(mutex);
get_cv.wait(lock, [&]() { return unlocked | (q.size() > 0); });
if (q.empty())
return std::move(emptyT);
auto tmp = std::move(q.front());
q.pop_front();
if (Max > 0) post_cv.notify_all();
return std::move(tmp.first);
}
void UnlockGetters()
{
unlocked = true;
get_cv.notify_all();
if (Max > 0) post_cv.notify_all();
}
int Size() const
{
std::lock_guard<std::mutex> 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);
}
};