mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 05:31:01 +00:00 
			
		
		
		
	 767e374dce
			
		
	
	
		767e374dce
		
	
	
	
	
		
			
			Since Embree v3.13.0 supports AARCH64, switch back to the official repo instead of using Embree-aarch64. `thirdparty/embree/patches/godot-changes.patch` should now contain an accurate diff of the changes done to the library.
		
			
				
	
	
		
			326 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2009-2021 Intel Corporation
 | |
| // SPDX-License-Identifier: Apache-2.0
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include "geometry.h"
 | |
| #include "buffer.h"
 | |
| #include "../subdiv/half_edge.h"
 | |
| #include "../subdiv/tessellation_cache.h"
 | |
| #include "../subdiv/catmullclark_coefficients.h"
 | |
| #include "../subdiv/patch.h"
 | |
| #include "../../common/algorithms/parallel_map.h"
 | |
| #include "../../common/algorithms/parallel_set.h"
 | |
| 
 | |
| namespace embree
 | |
| {
 | |
|   class SubdivMesh : public Geometry
 | |
|   {
 | |
|     ALIGNED_CLASS_(16);
 | |
|   public:
 | |
| 
 | |
|     typedef HalfEdge::Edge Edge;
 | |
|     
 | |
|     /*! type of this geometry */
 | |
|     static const Geometry::GTypeMask geom_type = Geometry::MTY_SUBDIV_MESH;
 | |
| 
 | |
|     /*! structure used to sort half edges using radix sort by their key */
 | |
|     struct KeyHalfEdge 
 | |
|     {
 | |
|       KeyHalfEdge() {}
 | |
|       
 | |
|       KeyHalfEdge (uint64_t key, HalfEdge* edge) 
 | |
|       : key(key), edge(edge) {}
 | |
|       
 | |
|       __forceinline operator uint64_t() const { 
 | |
| 	return key; 
 | |
|       }
 | |
| 
 | |
|       friend __forceinline bool operator<(const KeyHalfEdge& e0, const KeyHalfEdge& e1) {
 | |
|         return e0.key < e1.key;
 | |
|       }
 | |
|       
 | |
|     public:
 | |
|       uint64_t key;
 | |
|       HalfEdge* edge;
 | |
|     };
 | |
| 
 | |
|   public:
 | |
| 
 | |
|     /*! subdiv mesh construction */
 | |
|     SubdivMesh(Device* device);
 | |
| 
 | |
|   public:
 | |
|     void setMask (unsigned mask);
 | |
|     void setSubdivisionMode (unsigned int topologyID, RTCSubdivisionMode mode);
 | |
|     void setVertexAttributeTopology(unsigned int vertexAttribID, unsigned int topologyID);
 | |
|     void setNumTimeSteps (unsigned int numTimeSteps);
 | |
|     void setVertexAttributeCount (unsigned int N);
 | |
|     void setTopologyCount (unsigned int N);
 | |
|     void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
 | |
|     void* getBuffer(RTCBufferType type, unsigned int slot);
 | |
|     void updateBuffer(RTCBufferType type, unsigned int slot);
 | |
|     void setTessellationRate(float N);
 | |
|     bool verify();
 | |
|     void commit();
 | |
|     void addElementsToCount (GeometryCounts & counts) const;
 | |
|     void setDisplacementFunction (RTCDisplacementFunctionN func);
 | |
|     unsigned int getFirstHalfEdge(unsigned int faceID);
 | |
|     unsigned int getFace(unsigned int edgeID);
 | |
|     unsigned int getNextHalfEdge(unsigned int edgeID);
 | |
|     unsigned int getPreviousHalfEdge(unsigned int edgeID);
 | |
|     unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID);
 | |
| 
 | |
|   public:
 | |
| 
 | |
|     /*! return the number of faces */
 | |
|     size_t numFaces() const { 
 | |
|       return faceVertices.size(); 
 | |
|     }
 | |
| 
 | |
|     /*! return the number of edges */
 | |
|     size_t numEdges() const { 
 | |
|       return topology[0].vertexIndices.size(); 
 | |
|     }
 | |
| 
 | |
|     /*! return the number of vertices */
 | |
|     size_t numVertices() const { 
 | |
|       return vertices[0].size(); 
 | |
|     }
 | |
| 
 | |
|     /*! calculates the bounds of the i'th subdivision patch at the j'th timestep */
 | |
|     __forceinline BBox3fa bounds(size_t i, size_t j = 0) const {
 | |
|       return topology[0].getHalfEdge(i)->bounds(vertices[j]);
 | |
|     }
 | |
| 
 | |
|     /*! check if the i'th primitive is valid */
 | |
|     __forceinline bool valid(size_t i) const {
 | |
|       return topology[0].valid(i) && !invalidFace(i);
 | |
|     }
 | |
| 
 | |
|     /*! check if the i'th primitive is valid for the j'th time range */
 | |
|     __forceinline bool valid(size_t i, size_t j) const {
 | |
|       return topology[0].valid(i) && !invalidFace(i,j);
 | |
|     }
 | |
| 
 | |
|     /*! prints some statistics */
 | |
|     void printStatistics();
 | |
| 
 | |
|     /*! initializes the half edge data structure */
 | |
|     void initializeHalfEdgeStructures ();
 | |
|  
 | |
|   public:
 | |
| 
 | |
|     /*! returns the vertex buffer for some time step */
 | |
|     __forceinline const BufferView<Vec3fa>& getVertexBuffer( const size_t t = 0 ) const {
 | |
|       return vertices[t];
 | |
|     }
 | |
| 
 | |
|     /* returns tessellation level of edge */
 | |
|     __forceinline float getEdgeLevel(const size_t i) const
 | |
|     {
 | |
|       if (levels) return clamp(levels[i],1.0f,4096.0f); // FIXME: do we want to limit edge level?
 | |
|       else return clamp(tessellationRate,1.0f,4096.0f); // FIXME: do we want to limit edge level?
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     RTCDisplacementFunctionN displFunc;    //!< displacement function
 | |
| 
 | |
|     /*! all buffers in this section are provided by the application */
 | |
|   public:
 | |
|     
 | |
|     /*! the topology contains all data that may differ when
 | |
|      *  interpolating different user data buffers */
 | |
|     struct Topology
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|       /*! Default topology construction */
 | |
|       Topology () : halfEdges(nullptr,0) {}
 | |
| 
 | |
|       /*! Topology initialization */
 | |
|       Topology (SubdivMesh* mesh);
 | |
| 
 | |
|       /*! make the class movable */
 | |
|     public: 
 | |
|       Topology (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
 | |
|         : mesh(std::move(other.mesh)), 
 | |
|           vertexIndices(std::move(other.vertexIndices)),
 | |
|           subdiv_mode(std::move(other.subdiv_mode)),
 | |
|           halfEdges(std::move(other.halfEdges)),
 | |
|           halfEdges0(std::move(other.halfEdges0)),
 | |
|           halfEdges1(std::move(other.halfEdges1)) {}
 | |
|       
 | |
|       Topology& operator= (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
 | |
|       {
 | |
|         mesh = std::move(other.mesh); 
 | |
|         vertexIndices = std::move(other.vertexIndices);
 | |
|         subdiv_mode = std::move(other.subdiv_mode);
 | |
|         halfEdges = std::move(other.halfEdges);
 | |
|         halfEdges0 = std::move(other.halfEdges0);
 | |
|         halfEdges1 = std::move(other.halfEdges1);
 | |
|         return *this;
 | |
|       }
 | |
| 
 | |
|     public:
 | |
|       /*! check if the i'th primitive is valid in this topology */
 | |
|       __forceinline bool valid(size_t i) const 
 | |
|       {
 | |
|         if (unlikely(subdiv_mode == RTC_SUBDIVISION_MODE_NO_BOUNDARY)) {
 | |
|           if (getHalfEdge(i)->faceHasBorder()) return false;
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
|       
 | |
|       /*! updates the interpolation mode for the topology */
 | |
|       void setSubdivisionMode (RTCSubdivisionMode mode);
 | |
| 
 | |
|       /*! marks all buffers as modified */
 | |
|       void update ();
 | |
| 
 | |
|       /*! verifies index array */
 | |
|       bool verify (size_t numVertices);
 | |
| 
 | |
|       /*! initializes the half edge data structure */
 | |
|       void initializeHalfEdgeStructures ();
 | |
| 
 | |
|     private:
 | |
|       
 | |
|       /*! recalculates the half edges */
 | |
|       void calculateHalfEdges();
 | |
|       
 | |
|       /*! updates half edges when recalculation is not necessary */
 | |
|       void updateHalfEdges();
 | |
|       
 | |
|       /*! user input data */
 | |
|     public:
 | |
| 
 | |
|       SubdivMesh* mesh;
 | |
| 
 | |
|       /*! indices of the vertices composing each face */
 | |
|       BufferView<unsigned int> vertexIndices;
 | |
|       
 | |
|       /*! subdiv interpolation mode */
 | |
|       RTCSubdivisionMode subdiv_mode;
 | |
| 
 | |
|       /*! generated data */
 | |
|     public:
 | |
| 
 | |
|       /*! returns the start half edge for face f */
 | |
|       __forceinline const HalfEdge* getHalfEdge ( const size_t f ) const { 
 | |
|         return &halfEdges[mesh->faceStartEdge[f]]; 
 | |
|       }
 | |
| 
 | |
|       /*! Half edge structure, generated by initHalfEdgeStructures */
 | |
|       mvector<HalfEdge> halfEdges;
 | |
| 
 | |
|       /*! the following data is only required during construction of the
 | |
|        *  half edge structure and can be cleared for static scenes */
 | |
|     private:
 | |
|       
 | |
|       /*! two arrays used to sort the half edges */
 | |
|       std::vector<KeyHalfEdge> halfEdges0;
 | |
|       std::vector<KeyHalfEdge> halfEdges1;
 | |
|     };
 | |
| 
 | |
|     /*! returns the start half edge for topology t and face f */
 | |
|     __forceinline const HalfEdge* getHalfEdge ( const size_t t , const size_t f ) const { 
 | |
|       return topology[t].getHalfEdge(f);
 | |
|     }
 | |
| 
 | |
|     /*! buffer containing the number of vertices for each face */
 | |
|     BufferView<unsigned int> faceVertices;
 | |
| 
 | |
|     /*! array of topologies */
 | |
|     vector<Topology> topology;
 | |
| 
 | |
|     /*! vertex buffer (one buffer for each time step) */
 | |
|     vector<BufferView<Vec3fa>> vertices;
 | |
| 
 | |
|     /*! user data buffers */
 | |
|     vector<RawBufferView> vertexAttribs;
 | |
| 
 | |
|     /*! edge crease buffer containing edges (pairs of vertices) that carry edge crease weights */
 | |
|     BufferView<Edge> edge_creases;
 | |
|     
 | |
|     /*! edge crease weights for each edge of the edge_creases buffer */
 | |
|     BufferView<float> edge_crease_weights;
 | |
|     
 | |
|     /*! vertex crease buffer containing all vertices that carry vertex crease weights */
 | |
|     BufferView<unsigned int> vertex_creases;
 | |
|     
 | |
|     /*! vertex crease weights for each vertex of the vertex_creases buffer */
 | |
|     BufferView<float> vertex_crease_weights;
 | |
| 
 | |
|     /*! subdivision level for each half edge of the vertexIndices buffer */
 | |
|     BufferView<float> levels;
 | |
|     float tessellationRate;  // constant rate that is used when levels is not set
 | |
| 
 | |
|     /*! buffer that marks specific faces as holes */
 | |
|     BufferView<unsigned> holes;
 | |
| 
 | |
|     /*! all data in this section is generated by initializeHalfEdgeStructures function */
 | |
|   private:
 | |
| 
 | |
|     /*! number of half edges used by faces */
 | |
|     size_t numHalfEdges; 
 | |
| 
 | |
|     /*! fast lookup table to find the first half edge for some face */
 | |
|     mvector<uint32_t> faceStartEdge;
 | |
| 
 | |
|     /*! fast lookup table to find the face for some half edge */
 | |
|     mvector<uint32_t> halfEdgeFace;
 | |
| 
 | |
|     /*! set with all holes */
 | |
|     parallel_set<uint32_t> holeSet;
 | |
| 
 | |
|     /*! fast lookup table to detect invalid faces */
 | |
|     mvector<char> invalid_face;
 | |
| 
 | |
|     /*! test if face i is invalid in timestep j */
 | |
|     __forceinline       char& invalidFace(size_t i, size_t j = 0)       { return invalid_face[i*numTimeSteps+j]; }
 | |
|     __forceinline const char& invalidFace(size_t i, size_t j = 0) const { return invalid_face[i*numTimeSteps+j]; }
 | |
| 
 | |
|     /*! interpolation cache */
 | |
|   public:
 | |
|     static __forceinline size_t numInterpolationSlots4(size_t stride) { return (stride+15)/16; }
 | |
|     static __forceinline size_t numInterpolationSlots8(size_t stride) { return (stride+31)/32; }
 | |
|     static __forceinline size_t interpolationSlot(size_t prim, size_t slot, size_t stride) {
 | |
|       const size_t slots = numInterpolationSlots4(stride); 
 | |
|       assert(slot < slots); 
 | |
|       return slots*prim+slot;
 | |
|     }
 | |
|     std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_buffer_tags;
 | |
|     std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_attrib_buffer_tags;
 | |
|     std::vector<Patch3fa::Ref> patch_eval_trees;
 | |
|     
 | |
|     /*! the following data is only required during construction of the
 | |
|      *  half edge structure and can be cleared for static scenes */
 | |
|   private:
 | |
| 
 | |
|     /*! map with all vertex creases */
 | |
|     parallel_map<uint32_t,float> vertexCreaseMap;
 | |
|     
 | |
|     /*! map with all edge creases */
 | |
|     parallel_map<uint64_t,float> edgeCreaseMap;
 | |
| 
 | |
|   protected:
 | |
|     
 | |
|     /*! counts number of geometry commits */
 | |
|     size_t commitCounter;
 | |
|   };
 | |
| 
 | |
|   namespace isa
 | |
|   {
 | |
|     struct SubdivMeshISA : public SubdivMesh
 | |
|     {
 | |
|       SubdivMeshISA (Device* device)
 | |
|         : SubdivMesh(device) {}
 | |
| 
 | |
|       void interpolate(const RTCInterpolateArguments* const args);
 | |
|       void interpolateN(const RTCInterpolateNArguments* const args);
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   DECLARE_ISA_FUNCTION(SubdivMesh*, createSubdivMesh, Device*);
 | |
| };
 |