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