| 1 | // SuperTux |
| 2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.de> |
| 3 | // Copyright (C) 2018 Ingo Ruhnke <grumbel@gmail.com> |
| 4 | // |
| 5 | // This program is free software: you can redistribute it and/or modify |
| 6 | // it under the terms of the GNU General Public License as published by |
| 7 | // the Free Software Foundation, either version 3 of the License, or |
| 8 | // (at your option) any later version. |
| 9 | // |
| 10 | // This program is distributed in the hope that it will be useful, |
| 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | // GNU General Public License for more details. |
| 14 | // |
| 15 | // You should have received a copy of the GNU General Public License |
| 16 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | |
| 18 | #include "video/compositor.hpp" |
| 19 | |
| 20 | #include "math/rect.hpp" |
| 21 | #include "video/drawing_request.hpp" |
| 22 | #include "video/painter.hpp" |
| 23 | #include "video/renderer.hpp" |
| 24 | #include "video/video_system.hpp" |
| 25 | |
| 26 | bool Compositor::s_render_lighting = true; |
| 27 | |
| 28 | Compositor::Compositor(VideoSystem& video_system) : |
| 29 | m_video_system(video_system), |
| 30 | m_obst(), |
| 31 | m_drawing_contexts() |
| 32 | { |
| 33 | obstack_init(&m_obst); |
| 34 | } |
| 35 | |
| 36 | Compositor::~Compositor() |
| 37 | { |
| 38 | m_drawing_contexts.clear(); |
| 39 | obstack_free(&m_obst, nullptr); |
| 40 | } |
| 41 | |
| 42 | DrawingContext& |
| 43 | Compositor::make_context(bool overlay) |
| 44 | { |
| 45 | m_drawing_contexts.emplace_back(new DrawingContext(m_video_system, m_obst, overlay)); |
| 46 | return *m_drawing_contexts.back(); |
| 47 | } |
| 48 | |
| 49 | void |
| 50 | Compositor::render() |
| 51 | { |
| 52 | auto& lightmap = m_video_system.get_lightmap(); |
| 53 | |
| 54 | bool use_lightmap = std::any_of(m_drawing_contexts.begin(), m_drawing_contexts.end(), |
| 55 | [](std::unique_ptr<DrawingContext>& ctx){ |
| 56 | return ctx->use_lightmap(); |
| 57 | }); |
| 58 | |
| 59 | use_lightmap = use_lightmap && s_render_lighting; |
| 60 | |
| 61 | // prepare lightmap |
| 62 | if (use_lightmap) |
| 63 | { |
| 64 | lightmap.start_draw(); |
| 65 | Painter& painter = lightmap.get_painter(); |
| 66 | |
| 67 | for (auto& ctx : m_drawing_contexts) |
| 68 | { |
| 69 | if (!ctx->is_overlay()) |
| 70 | { |
| 71 | painter.set_clip_rect(ctx->get_viewport()); |
| 72 | painter.clear(ctx->get_ambient_color()); |
| 73 | |
| 74 | ctx->light().render(lightmap, Canvas::ALL); |
| 75 | |
| 76 | painter.clear_clip_rect(); |
| 77 | } |
| 78 | } |
| 79 | lightmap.end_draw(); |
| 80 | } |
| 81 | |
| 82 | auto back_renderer = m_video_system.get_back_renderer(); |
| 83 | if (back_renderer) |
| 84 | { |
| 85 | back_renderer->start_draw(); |
| 86 | |
| 87 | Painter& painter = back_renderer->get_painter(); |
| 88 | |
| 89 | for (auto& ctx : m_drawing_contexts) |
| 90 | { |
| 91 | painter.set_clip_rect(ctx->get_viewport()); |
| 92 | ctx->color().render(*back_renderer, Canvas::BELOW_LIGHTMAP); |
| 93 | painter.clear_clip_rect(); |
| 94 | } |
| 95 | |
| 96 | back_renderer->end_draw(); |
| 97 | } |
| 98 | |
| 99 | // compose the screen |
| 100 | { |
| 101 | auto& renderer = m_video_system.get_renderer(); |
| 102 | |
| 103 | renderer.start_draw(); |
| 104 | Painter& painter = renderer.get_painter(); |
| 105 | |
| 106 | for (auto& ctx : m_drawing_contexts) |
| 107 | { |
| 108 | painter.set_clip_rect(ctx->get_viewport()); |
| 109 | ctx->color().render(renderer, Canvas::BELOW_LIGHTMAP); |
| 110 | painter.clear_clip_rect(); |
| 111 | } |
| 112 | |
| 113 | if (use_lightmap) |
| 114 | { |
| 115 | const TexturePtr& texture = lightmap.get_texture(); |
| 116 | if (texture) |
| 117 | { |
| 118 | TextureRequest request; |
| 119 | |
| 120 | request.type = TEXTURE; |
| 121 | request.flip = 0; |
| 122 | request.alpha = 1.0f; |
| 123 | request.blend = Blend::MOD; |
| 124 | |
| 125 | request.srcrects.emplace_back(0, 0, |
| 126 | static_cast<float>(texture->get_image_width()), |
| 127 | static_cast<float>(texture->get_image_height())); |
| 128 | request.dstrects.emplace_back(Vector(0, 0), lightmap.get_logical_size()); |
| 129 | request.angles.emplace_back(0.0f); |
| 130 | |
| 131 | request.texture = texture.get(); |
| 132 | request.color = Color::WHITE; |
| 133 | |
| 134 | painter.draw_texture(request); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // Render overlay elements |
| 139 | for (auto& ctx : m_drawing_contexts) |
| 140 | { |
| 141 | painter.set_clip_rect(ctx->get_viewport()); |
| 142 | ctx->color().render(renderer, Canvas::ABOVE_LIGHTMAP); |
| 143 | painter.clear_clip_rect(); |
| 144 | } |
| 145 | |
| 146 | renderer.end_draw(); |
| 147 | } |
| 148 | |
| 149 | // cleanup |
| 150 | for (auto& ctx : m_drawing_contexts) |
| 151 | { |
| 152 | ctx->clear(); |
| 153 | } |
| 154 | m_video_system.flip(); |
| 155 | |
| 156 | obstack_free(&m_obst, nullptr); |
| 157 | obstack_init(&m_obst); |
| 158 | } |
| 159 | |
| 160 | /* EOF */ |
| 161 | |