1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2015 SuperTuxKart-Team
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #ifndef SERVER_ONLY
19 #include "graphics/draw_calls.hpp"
20
21 #include "config/stk_config.hpp"
22 #include "config/user_config.hpp"
23 #include "graphics/cpu_particle_manager.hpp"
24 #include "graphics/irr_driver.hpp"
25 #include "graphics/lod_node.hpp"
26 #include "graphics/shaders.hpp"
27 #include "graphics/stk_particle.hpp"
28 #include "graphics/stk_text_billboard.hpp"
29 #include "graphics/text_billboard_drawer.hpp"
30 #include "graphics/sp/sp_base.hpp"
31 #include "graphics/sp/sp_mesh_node.hpp"
32 #include "tracks/track.hpp"
33 #include "utils/profiler.hpp"
34
35 #include <numeric>
36
37 // ----------------------------------------------------------------------------
isCulledPrecise(const scene::ICameraSceneNode * cam,const scene::ISceneNode * node,bool visualization)38 bool DrawCalls::isCulledPrecise(const scene::ICameraSceneNode *cam,
39 const scene::ISceneNode* node,
40 bool visualization)
41 {
42 if (!node->getAutomaticCulling() && !visualization)
43 return false;
44
45 const core::matrix4 &trans = node->getAbsoluteTransformation();
46 core::vector3df edges[8];
47 node->getBoundingBox().getEdges(edges);
48 for (unsigned i = 0; i < 8; i++)
49 trans.transformVect(edges[i]);
50
51 /* From irrlicht
52 /3--------/7
53 / | / |
54 / | / |
55 1---------5 |
56 | /2- - -|- -6
57 | / | /
58 |/ | /
59 0---------4/
60 */
61
62 if (visualization)
63 {
64 addEdgeForViz(edges[0], edges[1]);
65 addEdgeForViz(edges[1], edges[5]);
66 addEdgeForViz(edges[5], edges[4]);
67 addEdgeForViz(edges[4], edges[0]);
68 addEdgeForViz(edges[2], edges[3]);
69 addEdgeForViz(edges[3], edges[7]);
70 addEdgeForViz(edges[7], edges[6]);
71 addEdgeForViz(edges[6], edges[2]);
72 addEdgeForViz(edges[0], edges[2]);
73 addEdgeForViz(edges[1], edges[3]);
74 addEdgeForViz(edges[5], edges[7]);
75 addEdgeForViz(edges[4], edges[6]);
76 if (!node->getAutomaticCulling())
77 {
78 return false;
79 }
80 }
81
82 const scene::SViewFrustum &frust = *cam->getViewFrustum();
83 for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; i++)
84 {
85 if (isBoxInFrontOfPlane(frust.planes[i], edges))
86 {
87 return true;
88 }
89 }
90 return false;
91
92 } // isCulledPrecise
93
94 // ----------------------------------------------------------------------------
isBoxInFrontOfPlane(const core::plane3df & plane,const core::vector3df * edges)95 bool DrawCalls::isBoxInFrontOfPlane(const core::plane3df &plane,
96 const core::vector3df* edges)
97 {
98 for (u32 i = 0; i < 8; i++)
99 {
100 if (plane.classifyPointRelation(edges[i]) != core::ISREL3D_FRONT)
101 return false;
102 }
103 return true;
104 } // isBoxInFrontOfPlane
105
106 // ----------------------------------------------------------------------------
addEdgeForViz(const core::vector3df & p0,const core::vector3df & p1)107 void DrawCalls::addEdgeForViz(const core::vector3df &p0,
108 const core::vector3df &p1)
109 {
110 m_bounding_boxes.push_back(p0.X);
111 m_bounding_boxes.push_back(p0.Y);
112 m_bounding_boxes.push_back(p0.Z);
113 m_bounding_boxes.push_back(p1.X);
114 m_bounding_boxes.push_back(p1.Y);
115 m_bounding_boxes.push_back(p1.Z);
116 } // addEdgeForViz
117
118 // ----------------------------------------------------------------------------
renderBoundingBoxes()119 void DrawCalls::renderBoundingBoxes()
120 {
121 Shaders::ColoredLine *line = Shaders::ColoredLine::getInstance();
122 line->use();
123 line->bindVertexArray();
124 line->bindBuffer();
125 line->setUniforms(irr::video::SColor(255, 255, 0, 0));
126 const float *tmp = m_bounding_boxes.data();
127 for (unsigned int i = 0; i < m_bounding_boxes.size(); i += 1024 * 6)
128 {
129 unsigned count = std::min((unsigned)m_bounding_boxes.size() - i,
130 (unsigned)1024 * 6);
131 glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(float), &tmp[i]);
132
133 glDrawArrays(GL_LINES, 0, count / 3);
134 }
135 m_bounding_boxes.clear();
136 } // renderBoundingBoxes
137
138 // ----------------------------------------------------------------------------
parseSceneManager(core::list<scene::ISceneNode * > & List,const scene::ICameraSceneNode * cam)139 void DrawCalls::parseSceneManager(core::list<scene::ISceneNode*> &List,
140 const scene::ICameraSceneNode *cam)
141 {
142 core::list<scene::ISceneNode*>::Iterator I = List.begin(), E = List.end();
143 for (; I != E; ++I)
144 {
145 if (LODNode *node = dynamic_cast<LODNode *>(*I))
146 {
147 node->updateVisibility();
148 }
149 (*I)->updateAbsolutePosition();
150 if (!(*I)->isVisible())
151 continue;
152
153 if (STKParticle *node = dynamic_cast<STKParticle*>(*I))
154 {
155 if (!isCulledPrecise(cam, *I, irr_driver->getBoundingBoxesViz()))
156 CPUParticleManager::getInstance()->addParticleNode(node);
157 continue;
158 }
159
160 if (scene::IBillboardSceneNode *node =
161 dynamic_cast<scene::IBillboardSceneNode*>(*I))
162 {
163 if (!isCulledPrecise(cam, *I))
164 CPUParticleManager::getInstance()->addBillboardNode(node);
165 continue;
166 }
167
168 if (STKTextBillboard *tb =
169 dynamic_cast<STKTextBillboard*>(*I))
170 {
171 if (!isCulledPrecise(cam, *I, irr_driver->getBoundingBoxesViz()))
172 TextBillboardDrawer::addTextBillboard(tb);
173 continue;
174 }
175
176 SP::SPMeshNode* node = dynamic_cast<SP::SPMeshNode*>(*I);
177 if (node)
178 {
179 SP::addObject(node);
180 }
181 parseSceneManager((*I)->getChildren(), cam);
182 }
183 }
184
185 // ----------------------------------------------------------------------------
DrawCalls()186 DrawCalls::DrawCalls()
187 {
188 m_sync = 0;
189 } //DrawCalls
190
191 // ----------------------------------------------------------------------------
~DrawCalls()192 DrawCalls::~DrawCalls()
193 {
194 CPUParticleManager::kill();
195 STKParticle::destroyFlipsBuffer();
196 } //~DrawCalls
197
198 // ----------------------------------------------------------------------------
199 /** Prepare draw calls before scene rendering
200 */
prepareDrawCalls(scene::ICameraSceneNode * camnode)201 void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
202 {
203 CPUParticleManager::getInstance()->reset();
204 TextBillboardDrawer::reset();
205 PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
206 SP::prepareDrawCalls();
207 parseSceneManager(
208 irr_driver->getSceneManager()->getRootSceneNode()->getChildren(),
209 camnode);
210 SP::handleDynamicDrawCall();
211 SP::updateModelMatrix();
212 PROFILER_POP_CPU_MARKER();
213
214 PROFILER_PUSH_CPU_MARKER("- cpu particle generation", 0x2F, 0x1F, 0x11);
215 CPUParticleManager::getInstance()->generateAll();
216 PROFILER_POP_CPU_MARKER();
217
218 // Add a 1 s timeout
219 if (m_sync != 0)
220 {
221 PROFILER_PUSH_CPU_MARKER("- Sync Stall", 0xFF, 0x0, 0x0);
222 GLenum reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
223 if (reason != GL_ALREADY_SIGNALED)
224 {
225 do
226 {
227 reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000);
228 }
229 while (reason == GL_TIMEOUT_EXPIRED);
230 }
231 glDeleteSync(m_sync);
232 m_sync = 0;
233 PROFILER_POP_CPU_MARKER();
234 }
235
236 PROFILER_PUSH_CPU_MARKER("- particle and text billboard upload", 0x3F,
237 0x03, 0x61);
238 CPUParticleManager::getInstance()->uploadAll();
239 TextBillboardDrawer::updateAll();
240 PROFILER_POP_CPU_MARKER();
241
242 PROFILER_PUSH_CPU_MARKER("- SP::upload instance and skinning matrices",
243 0xFF, 0x0, 0xFF);
244 SP::uploadAll();
245 PROFILER_POP_CPU_MARKER();
246 }
247
248 #endif
249