1 //******************************************************************************
2 ///
3 /// @file backend/bounding/boundingtask.cpp
4 ///
5 /// @todo What's in here?
6 ///
7 /// @copyright
8 /// @parblock
9 ///
10 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11 /// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
12 ///
13 /// POV-Ray is free software: you can redistribute it and/or modify
14 /// it under the terms of the GNU Affero General Public License as
15 /// published by the Free Software Foundation, either version 3 of the
16 /// License, or (at your option) any later version.
17 ///
18 /// POV-Ray is distributed in the hope that it will be useful,
19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 /// GNU Affero General Public License for more details.
22 ///
23 /// You should have received a copy of the GNU Affero General Public License
24 /// along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ///
26 /// ----------------------------------------------------------------------------
27 ///
28 /// POV-Ray is based on the popular DKB raytracer version 2.12.
29 /// DKBTrace was originally written by David K. Buck.
30 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
31 ///
32 /// @endparblock
33 ///
34 //------------------------------------------------------------------------------
35 // SPDX-License-Identifier: AGPL-3.0-or-later
36 //******************************************************************************
37
38 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
39 #include "backend/bounding/boundingtask.h"
40
41 // Standard C++ header files
42 #include <set>
43
44 // Boost header files
45 #include <boost/bind.hpp>
46 #if POV_MULTITHREADED
47 #include <boost/thread.hpp>
48 #endif
49
50 // POV-Ray header files (core module)
51 #include "core/bounding/bsptree.h"
52 #include "core/math/matrix.h"
53 #include "core/scene/object.h"
54 #include "core/scene/tracethreaddata.h"
55
56 // POV-Ray header files (POVMS module)
57 #include "povms/povmsid.h"
58
59 // POV-Ray header files (backend module)
60 #include "backend/scene/backendscenedata.h"
61 #include "backend/support/task.h"
62
63 // this must be the last file included
64 #include "base/povdebug.h"
65
66 namespace pov
67 {
68
69 class SceneObjects : public BSPTree::Objects
70 {
71 public:
72 vector<ObjectPtr> infinite;
73 vector<ObjectPtr> finite;
74 unsigned int numLights;
75
SceneObjects(vector<ObjectPtr> & objects)76 SceneObjects(vector<ObjectPtr>& objects)
77 {
78 numLights = 0;
79 for(vector<ObjectPtr>::iterator i(objects.begin()); i != objects.end(); i++)
80 {
81 if(Test_Flag((*i), INFINITE_FLAG))
82 {
83 infinite.push_back(*i);
84 if (((*i)->Type & LIGHT_SOURCE_OBJECT) != 0)
85 numLights++;
86 }
87 else
88 finite.push_back(*i);
89 }
90 }
91
~SceneObjects()92 virtual ~SceneObjects()
93 {
94 // nothing to do
95 }
96
size() const97 virtual unsigned int size() const
98 {
99 return finite.size();
100 }
101
GetMin(unsigned int axis,unsigned int i) const102 virtual float GetMin(unsigned int axis, unsigned int i) const
103 {
104 return finite[i]->BBox.lowerLeft[axis];
105 }
106
GetMax(unsigned int axis,unsigned int i) const107 virtual float GetMax(unsigned int axis, unsigned int i) const
108 {
109 return (finite[i]->BBox.lowerLeft[axis] + finite[i]->BBox.size[axis]);
110 }
111 };
112
113 class BSPProgress : public BSPTree::Progress
114 {
115 public:
BSPProgress(RenderBackend::SceneId sid,POVMSAddress addr,Task & task)116 BSPProgress(RenderBackend::SceneId sid, POVMSAddress addr, Task& task) :
117 mTask(task),
118 sceneId(sid),
119 frontendAddress(addr),
120 lastProgressTime(0)
121 {
122 }
123
operator ()(unsigned int nodes) const124 virtual void operator()(unsigned int nodes) const
125 {
126 if((timer.ElapsedRealTime() - lastProgressTime) > 1000) // update progress at most every second
127 {
128 POVMS_Object obj(kPOVObjectClass_BoundingProgress);
129 obj.SetLong(kPOVAttrib_RealTime, timer.ElapsedRealTime());
130 obj.SetLong(kPOVAttrib_CurrentNodeCount, nodes);
131 RenderBackend::SendSceneOutput(sceneId, frontendAddress, kPOVMsgIdent_Progress, obj);
132
133 mTask.Cooperate();
134
135 lastProgressTime = timer.ElapsedRealTime();
136 }
137 }
138 private:
139 Task& mTask;
140 RenderBackend::SceneId sceneId;
141 POVMSAddress frontendAddress;
142 Timer timer;
143 mutable POV_LONG lastProgressTime;
144
145 BSPProgress();
146 };
147
BoundingTask(shared_ptr<BackendSceneData> sd,unsigned int bt,size_t seed)148 BoundingTask::BoundingTask(shared_ptr<BackendSceneData> sd, unsigned int bt, size_t seed) :
149 SceneTask(new TraceThreadData(dynamic_pointer_cast<SceneData>(sd), seed), boost::bind(&BoundingTask::SendFatalError, this, _1), "Bounding", sd),
150 sceneData(sd),
151 boundingThreshold(bt)
152 {
153 }
154
~BoundingTask()155 BoundingTask::~BoundingTask()
156 {
157 }
158
AppendObject(ObjectPtr p)159 void BoundingTask::AppendObject(ObjectPtr p)
160 {
161 sceneData->objects.push_back(p);
162 }
163
Run()164 void BoundingTask::Run()
165 {
166 if((sceneData->objects.size() < boundingThreshold) || (sceneData->boundingMethod == 0))
167 {
168 SceneObjects objects(sceneData->objects);
169 sceneData->boundingMethod = 0;
170 sceneData->numberOfFiniteObjects = objects.finite.size();
171 sceneData->numberOfInfiniteObjects = objects.infinite.size() - objects.numLights;
172 return;
173 }
174
175 switch(sceneData->boundingMethod)
176 {
177 case 2:
178 {
179 // new BSP tree code
180 SceneObjects objects(sceneData->objects);
181 BSPProgress progress(sceneData->sceneId, sceneData->frontendAddress, *this);
182
183 sceneData->objects.clear();
184 sceneData->objects.insert(sceneData->objects.end(), objects.finite.begin(), objects.finite.end());
185 sceneData->objects.insert(sceneData->objects.end(), objects.infinite.begin(), objects.infinite.end());
186 sceneData->numberOfFiniteObjects = objects.finite.size();
187 sceneData->numberOfInfiniteObjects = objects.infinite.size() - objects.numLights;
188 sceneData->tree = new BSPTree(sceneData->bspMaxDepth, sceneData->bspObjectIsectCost, sceneData->bspBaseAccessCost, sceneData->bspChildAccessCost, sceneData->bspMissChance);
189 sceneData->tree->build(progress, objects,
190 sceneData->nodes, sceneData->splitNodes, sceneData->objectNodes, sceneData->emptyNodes,
191 sceneData->maxObjects, sceneData->averageObjects, sceneData->maxDepth, sceneData->averageDepth,
192 sceneData->aborts, sceneData->averageAborts, sceneData->averageAbortObjects, sceneData->inputFile);
193 break;
194 }
195 case 1:
196 {
197 // old bounding box code
198 unsigned int numberOfLightSources;
199
200 Build_Bounding_Slabs(&(sceneData->boundingSlabs), sceneData->objects, sceneData->numberOfFiniteObjects,
201 sceneData->numberOfInfiniteObjects, numberOfLightSources);
202 break;
203 }
204 }
205 }
206
Stopped()207 void BoundingTask::Stopped()
208 {
209 }
210
Finish()211 void BoundingTask::Finish()
212 {
213 GetSceneDataPtr()->timeType = TraceThreadData::kBoundingTime;
214 GetSceneDataPtr()->realTime = ConsumedRealTime();
215 GetSceneDataPtr()->cpuTime = ConsumedCPUTime();
216 }
217
SendFatalError(Exception & e)218 void BoundingTask::SendFatalError(Exception& e)
219 {
220 // if the front-end has been told about this exception already, we don't tell it again
221 if (e.frontendnotified(true))
222 return;
223
224 POVMS_Message msg(kPOVObjectClass_ControlData, kPOVMsgClass_SceneOutput, kPOVMsgIdent_Error);
225
226 msg.SetString(kPOVAttrib_EnglishText, e.what());
227 msg.SetInt(kPOVAttrib_Error, 0);
228 msg.SetInt(kPOVAttrib_SceneId, sceneData->sceneId);
229 msg.SetSourceAddress(sceneData->backendAddress);
230 msg.SetDestinationAddress(sceneData->frontendAddress);
231
232 POVMS_SendMessage(msg);
233 }
234
235 } // end of namespace
236