// // RenderablePolyVoxEntityItem.h // libraries/entities-renderer/src/ // // Created by Seth Alves on 5/19/15. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_RenderablePolyVoxEntityItem_h #define hifi_RenderablePolyVoxEntityItem_h #include #include #include #include #include #include #include #include #include "RenderableEntityItem.h" class PolyVoxPayload { public: static uint8_t CUSTOM_PIPELINE_NUMBER; static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key); static void registerShapePipeline() { if (!CUSTOM_PIPELINE_NUMBER) { CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory); } } static const int MATERIAL_GPU_SLOT = 3; static std::shared_ptr _pipeline; static std::shared_ptr _wireframePipeline; PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { } typedef render::Payload Payload; typedef Payload::DataPointer Pointer; EntityItemPointer _owner; AABox _bounds; }; namespace render { template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload); template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args); template <> const ShapeKey shapeGetShapeKey(const PolyVoxPayload::Pointer& payload); } class RenderablePolyVoxEntityItem : public PolyVoxEntityItem, public RenderableEntityInterface { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderablePolyVoxEntityItem(const EntityItemID& entityItemID); virtual ~RenderablePolyVoxEntityItem(); RenderableEntityInterface* getRenderableInterface() override { return this; } void initializePolyVox(); virtual void somethingChangedNotification() override { // This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing // this entity comes from the entity-server. It gets called even if nothing has actually changed // (see the comment in EntityItem.cpp). If that gets fixed, this could be used to know if we // need to redo the voxel data. // _needsModelReload = true; } virtual uint8_t getVoxel(int x, int y, int z) override; virtual bool setVoxel(int x, int y, int z, uint8_t toValue) override; int getOnCount() const override { return _onCount; } void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; virtual void setVoxelData(QByteArray voxelData) override; virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) override; virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override; glm::vec3 getSurfacePositionAdjustment() const; glm::mat4 voxelToWorldMatrix() const; glm::mat4 worldToVoxelMatrix() const; glm::mat4 voxelToLocalMatrix() const; glm::mat4 localToVoxelMatrix() const; virtual ShapeType getShapeType() const override; virtual bool shouldBePhysical() const override { return !isDead(); } virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const override; virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3& worldCoords) const override; virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const override; virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3& localCoords) const override; // coords are in voxel-volume space virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) override; virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue) override; // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) override; virtual bool setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, float radiusWorldCoords, uint8_t toValue) override; virtual bool setAll(uint8_t toValue) override; virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override; virtual void setXTextureURL(const QString& xTextureURL) override; virtual void setYTextureURL(const QString& yTextureURL) override; virtual void setZTextureURL(const QString& zTextureURL) override; virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override; virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override; virtual void setXNNeighborID(const EntityItemID& xNNeighborID) override; virtual void setYNNeighborID(const EntityItemID& yNNeighborID) override; virtual void setZNNeighborID(const EntityItemID& zNNeighborID) override; virtual void setXPNeighborID(const EntityItemID& xPNeighborID) override; virtual void setYPNeighborID(const EntityItemID& yPNeighborID) override; virtual void setZPNeighborID(const EntityItemID& zPNeighborID) override; std::shared_ptr getXNNeighbor(); std::shared_ptr getYNNeighbor(); std::shared_ptr getZNNeighbor(); std::shared_ptr getXPNeighbor(); std::shared_ptr getYPNeighbor(); std::shared_ptr getZPNeighbor(); virtual void updateRegistrationPoint(const glm::vec3& value) override; void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize); void forEachVoxelValue(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize, std::function thunk); QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } uint8_t getVoxelInternal(int x, int y, int z) const; bool setVoxelInternal(int x, int y, int z, uint8_t toValue); void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); } // Transparent polyvox didn't seem to be working so disable for now bool isTransparent() override { return false; } bool getMeshes(MeshProxyList& result) override; protected: virtual void locationChanged(bool tellPhysics = true) override; private: // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions // may not match _voxelVolumeSize. model::MeshPointer _mesh; gpu::Stream::FormatPointer _vertexFormat; bool _meshDirty { true }; // does collision-shape need to be recomputed? bool _meshReady { false }; NetworkTexturePointer _xTexture; NetworkTexturePointer _yTexture; NetworkTexturePointer _zTexture; render::ItemID _myItem{ render::Item::INVALID_ITEM_ID }; ShapeInfo _shapeInfo; PolyVox::SimpleVolume* _volData = nullptr; bool _volDataDirty = false; // does recomputeMesh need to be called? int _onCount; // how many non-zero voxels are in _volData bool _neighborsNeedUpdate { false }; bool updateOnCount(int x, int y, int z, uint8_t toValue); PolyVox::RaycastResult doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, glm::vec4& result) const; // these are run off the main thread void decompressVolumeData(); void compressVolumeDataAndSendEditPacket(); virtual void recomputeMesh() override; // recompute mesh void computeShapeInfoWorker(); // these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID EntityItemWeakPointer _xNNeighbor; // neighbor found by going along negative X axis EntityItemWeakPointer _yNNeighbor; EntityItemWeakPointer _zNNeighbor; EntityItemWeakPointer _xPNeighbor; // neighbor found by going along positive X axis EntityItemWeakPointer _yPNeighbor; EntityItemWeakPointer _zPNeighbor; void cacheNeighbors(); void copyUpperEdgesFromNeighbors(); void bonkNeighbors(); bool updateDependents(); }; bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, int x, int y, int z); #endif // hifi_RenderablePolyVoxEntityItem_h