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 | |