// // Lol Engine // // Copyright © 2010—2016 Sam Hocevar // // Lol Engine is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it // and/or modify it under the terms of the Do What the Fuck You Want // to Public License, Version 2, as published by the WTFPL Task Force. // See http://www.wtfpl.net/ for more details. // #include #include #if defined _WIN32 # define WIN32_LEAN_AND_MEAN 1 # include # undef WIN32_LEAN_AND_MEAN # undef near /* Fuck Microsoft */ # undef far /* Fuck Microsoft again */ #endif #include "lolgl.h" namespace lol { /* * The global g_renderers object, initialised by Video::Setup */ //Renderer *g_renderer = nullptr; array g_renderers; /* * Private RendererData class */ class RendererData { friend class Renderer; private: ibox2 m_viewport; vec4 m_clear_color; float m_clear_depth; AlphaFunc m_alpha_func; float m_alpha_value; BlendEquation m_blend_rgb, m_blend_alpha; BlendFunc m_blend_src, m_blend_dst; DepthFunc m_depth_func; DepthMask m_depth_mask; CullMode m_cull_mode; PolygonMode m_polygon_mode; ScissorMode m_scissor_mode; vec4 m_scissor_rect; }; /* * Public Renderer class */ Renderer::Renderer(ivec2 size) : m_data(new RendererData()) { #if defined LOL_USE_GLEW && !defined __APPLE__ /* Initialise GLEW if necessary */ GLenum glerr = glewInit(); if (glerr != GLEW_OK) { msg::error("cannot initialise GLEW: %s\n", glewGetErrorString(glerr)); exit(EXIT_FAILURE); } #endif /* Initialise rendering states */ m_data->m_viewport = ibox2(0, 0, 0, 0); SetViewport(ibox2(ivec2::zero, size)); m_data->m_clear_color = vec4(-1.f); SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f)); m_data->m_clear_depth = -1.f; SetClearDepth(1.f); m_data->m_alpha_func = AlphaFunc::Never; m_data->m_alpha_value = -1.0f; SetAlphaFunc(AlphaFunc::Disabled, 0.0f); m_data->m_blend_rgb = BlendEquation::Subtract; m_data->m_blend_alpha = BlendEquation::Subtract; SetBlendEquation(BlendEquation::Add, BlendEquation::Add); m_data->m_blend_src = BlendFunc::Disabled; m_data->m_blend_dst = BlendFunc::Disabled; SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha); m_data->m_depth_func = DepthFunc::Disabled; SetDepthFunc(DepthFunc::LessOrEqual); m_data->m_depth_mask = DepthMask::Disabled; SetDepthMask(DepthMask::Enabled); m_data->m_cull_mode = CullMode::Disabled; SetCullMode(CullMode::Clockwise); m_data->m_polygon_mode = PolygonMode::Point; SetPolygonMode(PolygonMode::Fill); m_data->m_scissor_mode = ScissorMode::Disabled; SetPolygonMode(PolygonMode::Fill); /* Add some rendering states that we don't export to the user */ #if defined HAVE_GL_2X && !defined __APPLE__ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); #endif } Renderer::~Renderer() { delete m_data; } /* * Buffer clearing */ void Renderer::Clear(ClearMask mask) { GLbitfield m = 0; if (mask & ClearMask::Color) m |= GL_COLOR_BUFFER_BIT; if (mask & ClearMask::Depth) m |= GL_DEPTH_BUFFER_BIT; if (mask & ClearMask::Stencil) m |= GL_STENCIL_BUFFER_BIT; glClear(m); } /* * Renderer static */ void Renderer::AddNew(ivec2 size) { g_renderers << new Renderer(size); } int Renderer::GetCount() { return g_renderers.count(); } Renderer* Renderer::Get(int index) { return g_renderers[index]; } void Renderer::DestroyAll() { for (Renderer* renderer : g_renderers) delete renderer; g_renderers.empty(); } /* * Viewport dimensions */ void Renderer::SetViewport(ibox2 viewport) { if (m_data->m_viewport == viewport) return; glViewport(viewport.aa.x, viewport.aa.y, viewport.bb.x, viewport.bb.y); m_data->m_viewport = viewport; } ibox2 Renderer::GetViewport() const { return m_data->m_viewport; } float Renderer::GetXYRatio() const { ivec2 s = GetViewport().extent(); return (float)s.x / s.y; } float Renderer::GetYXRatio() const { ivec2 s = GetViewport().extent(); return (float)s.y / s.x; } /* * Clear color */ void Renderer::SetClearColor(vec4 color) { if (m_data->m_clear_color == color) return; glClearColor(color.r, color.g, color.b, color.a); m_data->m_clear_color = color; } vec4 Renderer::GetClearColor() const { return m_data->m_clear_color; } /* * Clear depth */ void Renderer::SetClearDepth(float depth) { if (m_data->m_clear_depth == depth) return; #if defined HAVE_GLES_2X glClearDepthf(depth); #else glClearDepth(depth); #endif m_data->m_clear_depth = depth; } float Renderer::GetClearDepth() const { return m_data->m_clear_depth; } /* * Alpha testing */ void Renderer::SetAlphaFunc(AlphaFunc func, float alpha) { if (m_data->m_alpha_func == func && m_data->m_alpha_value == alpha) return; #if defined HAVE_GLES_2X /* not supported */ #elif defined GL_VERSION_1_1 switch (func) { case AlphaFunc::Disabled: break; /* Nothing to do */ case AlphaFunc::Never: glAlphaFunc(GL_NEVER, alpha); break; case AlphaFunc::Less: glAlphaFunc(GL_LESS, alpha); break; case AlphaFunc::Equal: glAlphaFunc(GL_EQUAL, alpha); break; case AlphaFunc::LessOrEqual: glAlphaFunc(GL_LEQUAL, alpha); break; case AlphaFunc::Greater: glAlphaFunc(GL_GREATER, alpha); break; case AlphaFunc::NotEqual: glAlphaFunc(GL_NOTEQUAL, alpha); break; case AlphaFunc::GreaterOrEqual: glAlphaFunc(GL_GEQUAL, alpha); break; case AlphaFunc::Always: glAlphaFunc(GL_ALWAYS, alpha); break; } if (func == AlphaFunc::Disabled) glDisable(GL_ALPHA_TEST); else glEnable(GL_ALPHA_TEST); #else /* XXX: alpha test not available in GL ES and deprecated anyway. */ #endif m_data->m_alpha_func = func; m_data->m_alpha_value = alpha; } AlphaFunc Renderer::GetAlphaFunc() const { return m_data->m_alpha_func; } float Renderer::GetAlphaValue() const { return m_data->m_alpha_value; } /* * Blend equation */ void Renderer::SetBlendEquation(BlendEquation rgb, BlendEquation alpha) { if (m_data->m_blend_rgb == rgb && m_data->m_blend_alpha == alpha) return; GLenum s1[2] = { GL_FUNC_ADD, GL_FUNC_ADD }; BlendEquation s2[2] = { rgb, alpha }; for (int i = 0; i < 2; ++i) { switch (s2[i]) { case BlendEquation::Add: s1[i] = GL_FUNC_ADD; break; case BlendEquation::Subtract: s1[i] = GL_FUNC_SUBTRACT; break; case BlendEquation::ReverseSubtract: s1[i] = GL_FUNC_REVERSE_SUBTRACT; break; #if defined GL_MIN && defined GL_MAX case BlendEquation::Min: s1[i] = GL_MIN; break; case BlendEquation::Max: s1[i] = GL_MAX; break; #else case BlendEquation::Min: s1[i] = GL_MIN_EXT; break; case BlendEquation::Max: s1[i] = GL_MAX_EXT; break; #endif } } glBlendEquationSeparate(s1[0], s1[1]); m_data->m_blend_rgb = rgb; m_data->m_blend_alpha = alpha; } BlendEquation Renderer::GetBlendEquationRgb() const { return m_data->m_blend_rgb; } BlendEquation Renderer::GetBlendEquationAlpha() const { return m_data->m_blend_alpha; } /* * Blend function */ void Renderer::SetBlendFunc(BlendFunc src, BlendFunc dst) { if (m_data->m_blend_src == src && m_data->m_blend_dst == dst) return; GLenum s1[2] = { GL_ONE, GL_ZERO }; BlendFunc s2[2] = { src, dst }; for (int i = 0; i < 2; ++i) { switch (s2[i]) { case BlendFunc::Disabled: break; /* Nothing to do */ case BlendFunc::Zero: s1[i] = GL_ZERO; break; case BlendFunc::One: s1[i] = GL_ONE; break; case BlendFunc::SrcColor: s1[i] = GL_SRC_COLOR; break; case BlendFunc::OneMinusSrcColor: s1[i] = GL_ONE_MINUS_SRC_COLOR; break; case BlendFunc::DstColor: s1[i] = GL_DST_COLOR; break; case BlendFunc::OneMinusDstColor: s1[i] = GL_ONE_MINUS_DST_COLOR; break; case BlendFunc::SrcAlpha: s1[i] = GL_SRC_ALPHA; break; case BlendFunc::OneMinusSrcAlpha: s1[i] = GL_ONE_MINUS_SRC_ALPHA; break; case BlendFunc::DstAlpha: s1[i] = GL_DST_ALPHA; break; case BlendFunc::OneMinusDstAlpha: s1[i] = GL_ONE_MINUS_DST_ALPHA; break; case BlendFunc::ConstantColor: s1[i] = GL_CONSTANT_COLOR; break; case BlendFunc::OneMinusConstantColor: s1[i] = GL_ONE_MINUS_CONSTANT_COLOR; break; case BlendFunc::ConstantAlpha: s1[i] = GL_CONSTANT_ALPHA; break; case BlendFunc::OneMinusConstantAlpha: s1[i] = GL_ONE_MINUS_CONSTANT_ALPHA; break; } } if (src == BlendFunc::Disabled) { glDisable(GL_BLEND); } else { glEnable(GL_BLEND); glBlendFunc(s1[0], s1[1]); } m_data->m_blend_src = src; m_data->m_blend_dst = dst; } BlendFunc Renderer::GetBlendFuncSrc() const { return m_data->m_blend_src; } BlendFunc Renderer::GetBlendFuncDst() const { return m_data->m_blend_dst; } /* * Depth test */ void Renderer::SetDepthFunc(DepthFunc func) { if (m_data->m_depth_func == func) return; switch (func) { case DepthFunc::Disabled: break; /* Nothing to do */ case DepthFunc::Never: glDepthFunc(GL_NEVER); break; case DepthFunc::Less: glDepthFunc(GL_LESS); break; case DepthFunc::Equal: glDepthFunc(GL_EQUAL); break; case DepthFunc::LessOrEqual: glDepthFunc(GL_LEQUAL); break; case DepthFunc::Greater: glDepthFunc(GL_GREATER); break; case DepthFunc::NotEqual: glDepthFunc(GL_NOTEQUAL); break; case DepthFunc::GreaterOrEqual: glDepthFunc(GL_GEQUAL); break; case DepthFunc::Always: glDepthFunc(GL_ALWAYS); break; } if (func == DepthFunc::Disabled) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); m_data->m_depth_func = func; } DepthFunc Renderer::GetDepthFunc() const { return m_data->m_depth_func; } /* * Depth mask */ void Renderer::SetDepthMask(DepthMask mask) { if (m_data->m_depth_mask == mask) return; if (mask == DepthMask::Disabled) glDepthMask(GL_FALSE); else glDepthMask(GL_TRUE); m_data->m_depth_mask = mask; } DepthMask Renderer::GetDepthMask() const { return m_data->m_depth_mask; } /* * Face culling */ void Renderer::SetCullMode(CullMode mode) { if (m_data->m_cull_mode == mode) return; switch (mode) { case CullMode::Disabled: glDisable(GL_CULL_FACE); break; case CullMode::Clockwise: glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glFrontFace(GL_CW); break; case CullMode::CounterClockwise: glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glFrontFace(GL_CCW); break; } m_data->m_cull_mode = mode; } CullMode Renderer::GetCullMode() const { return m_data->m_cull_mode; } /* * Polygon rendering mode */ void Renderer::SetPolygonMode(PolygonMode mode) { if (m_data->m_polygon_mode == mode) return; #if defined HAVE_GLES_2X /* not supported */ #elif defined GL_VERSION_1_1 switch (mode) { case PolygonMode::Point: glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break; case PolygonMode::Line: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; case PolygonMode::Fill: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; } #endif m_data->m_polygon_mode = mode; } PolygonMode Renderer::GetPolygonMode() const { return m_data->m_polygon_mode; } /* * Scissor test mode */ void Renderer::SetScissorMode(ScissorMode mode) { if (m_data->m_scissor_mode == mode) return; if (mode == ScissorMode::Enabled) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); m_data->m_scissor_mode = mode; } void Renderer::SetScissorRect(vec4 rect) { m_data->m_scissor_rect = rect; if (m_data->m_scissor_mode == ScissorMode::Enabled) { glScissor((int)rect.x, (int)Video::GetSize().y - rect.w, (int)(rect.z - rect.x), (int)(rect.w - rect.y)); //glScissor((int)rect.x, (int)rect.y, (int)(rect.z - rect.x), (int)(rect.w - rect.y)); } } ScissorMode Renderer::GetScissorMode() const { return m_data->m_scissor_mode; } vec4 Renderer::GetScissorRect() const { return m_data->m_scissor_rect; } } /* namespace lol */