diff --git a/nel/include/nel/3d/decal.h b/nel/include/nel/3d/decal.h new file mode 100644 index 0000000000..e9a00d2fad --- /dev/null +++ b/nel/include/nel/3d/decal.h @@ -0,0 +1,386 @@ +/** \file decal.h + * Projected texture decal system for NeL 3D. + * + * Based on the design from the intern report by Christopher Tarento (2007). + * Decals project textures onto scene geometry using a unit-cube bounding box, + * quad-grid face selection, and batched rendering through CDecalManager. + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef NL_DECAL_H +#define NL_DECAL_H + + +#include "nel/3d/transform.h" + +#include "nel/3d/material.h" +#include "nel/3d/vertex_buffer.h" +#include "nel/3d/index_buffer.h" +#include "nel/3d/u_driver.h" +#include "nel/3d/shadow_poly_receiver.h" +#include "nel/misc/polygon.h" + + +namespace NLMISC +{ + +class CPlane; + +} + + +namespace NL3D +{ + +class CScene; +class CDecalManager; + +class UScene; +class UDriver; + + +// *************************************************************************** +const NLMISC::CClassId DecalId=NLMISC::CClassId(0x6a570fe6, 0x32323e16); + + +// *************************************************************************** +/// Clipping mode for decal face selection (see PDF §4.5.2) +enum TDecalClipMode +{ + /// No clipping: selected faces are used as-is + DecalClipNone = 0, + /// Mask clipping: use a second texture stage as a mask to delimit edges (preserves geometry, saves CPU) + DecalClipMask, + /// Geometry clipping: clip vertices against bounding box planes (saves fillrate, costs CPU) + DecalClipGeometry +}; + + +// *************************************************************************** +/** + * Context for decal face selection through visual collision. + * Carries clip planes, bounding box, and destination triangle list. + * \author Christopher Tarento + * \author Nevrax France + * \date 2007 + */ +class CDecalContext +{ +public: + CDecalContext(); + +public: + std::vector WorldClipPlanes; + CAABBox WorldBBox; + NLMISC::CPolygon2D Poly2D; + CMatrix WorldMatrix; + std::vector *DestTris; + TDecalClipMode ClipMode; + bool ClipDownFacing; +}; + + +// *************************************************************************** +/** + * A projected texture decal in the scene graph. + * + * The decal is a CTransform-based model with a unit-cube projection volume. + * It overrides traverseClip() for bounding-sphere frustum culling (§.6.1) + * and traverseRender() to register with CDecalManager for batched rendering. + * + * Face selection uses quad-grid + clip-plane refinement via CVisualCollisionMesh. + * UV coordinates are generated from the inverse world matrix of the unit cube (§4.5.3). + * + * Supports a vertex program for distance-based attenuation, bottom/top Z blending, + * and per-vertex diffuse color (ported from the legacy CLegacyDecal system). + * + * \author Christopher Tarento + * \author Nevrax France + * \date 2007 + */ +class CDecal : public CTransform +{ +public: + /// Constructor + CDecal(); + + /// Destructor + ~CDecal(); + + /// Initialization after insertion in scene graph. + void initModel(); + + /// Register CDecal as a valid model type for scene auto-registration. + static void registerBasic(); + + /** Clip method override. + * Uses bounding sphere vs frustum test for fast culling (see PDF §.6.1). + * \return true if the decal is visible + */ + bool clip(); + + /** Render traversal. + * Registers this decal with the CDecalManager for batched rendering. + */ + void traverseRender(); + + /// Get the decal's material (for texture/blend setup). + CMaterial &getMaterial() { return _Mat; } + + /** Get the decal's material ID for batching. + * Decals sharing the same material ID are batched together in the manager. + */ + uint32 getMaterialId() const { return _MaterialId; } + + /** Set the decal's material ID. + * This ID is assigned when registering a material with CDecalManager. + */ + void setMaterialId(uint32 id) { _MaterialId = id; } + + /** Set the decal texture from a filename. + * \param filename Path to the texture file. + */ + void setTexture(const std::string &filename); + + /** Get vertices and UVs for rendering. + * Recomputes if the decal is touched (moved or camera moved beyond threshold). + * \return vector of vertices (position interleaved, 3 per triangle) + */ + std::vector &getVertices(const bool useVertexProgram); + + /** Get UV coordinates corresponding to the vertices. + * Valid after calling getVertices(). + * \return vector of UV coordinates (one per vertex) + */ + const std::vector &getUVs() const { return _UVs; } + + /** Get per-vertex RGBA colors corresponding to the vertices. + * Valid after calling getVertices(). Contains diffuse color + computed alpha + * (distance attenuation × bottom blend × top blend). + * Used by the CPU fallback path when vertex programs are not available. + * \return vector of RGBA colors (one per vertex) + */ + const std::vector &getColors() const { return _Colors; } + + /** Set UV sub-region within a texture atlas. + * \param uv1 Top-left UV coordinate + * \param uv2 Bottom-right UV coordinate + */ + void setUVCoord(const CUV uv1, const CUV uv2); + + /** Set the clipping mode for face selection. + * \param mode One of DecalClipNone, DecalClipMask, DecalClipGeometry + */ + void setClippingMode(TDecalClipMode mode) { _DecalContext.ClipMode = mode; } + + /// Get the current clipping mode. + TDecalClipMode getClippingMode() const { return _DecalContext.ClipMode; } + + /** Mark this decal as static for caching optimization. + * Static decals only recompute geometry when first created or when + * the camera moves beyond the visibility distance threshold (see PDF §4.5.4). + * \param isStatic true for static decals + */ + void setStatic(const bool isStatic) { _IsStatic = isStatic; } + + /// Return whether this decal is marked static. + bool isStatic() const { return _IsStatic; } + + /** Set the render priority (0 = highest, 7 = lowest). + * Decals with lower priority values are rendered first within their material group. + * \param priority Value in [0, 7] + */ + void setPriority(uint8 priority) { _Priority = (priority < 8) ? priority : 7; } + + /// Get the current render priority. + uint8 getPriority() const { return _Priority; } + + /** Set whether downward-facing surfaces should be clipped. + * When enabled, triangles whose normal has a negative Z component + * are excluded from the decal projection. + * \param clipDownFacing true to clip down-facing surfaces + */ + void setClipDownFacing(bool clipDownFacing) { _ClipDownFacing = clipDownFacing; } + + /// Get whether down-facing clip is enabled. + bool getClipDownFacing() const { return _ClipDownFacing; } + + /** Set a custom UV matrix (world → UV transform). + * When enabled, this matrix replaces the default inverse-world UV generation. + * \param on true to enable, false to return to default UV generation + * \param matrix The world-to-UV matrix (only used when on=true) + */ + void setCustomUVMatrix(bool on, const CMatrix &matrix = CMatrix::Identity); + + /** Set the texture coordinate transform matrix. + * Applied to the UV generation pipeline (multiplied with the inverse-world matrix). + * \param matrix The texture transform matrix + */ + void setTextureMatrix(const CMatrix &matrix); + + /** Set the world matrix for an arrow-shaped decal. + * Convenience method that computes a world matrix for a decal stretched + * from start to end with the given half-width. + * \param start 2D start position + * \param end 2D end position + * \param halfWidth Half-width of the arrow + */ + void setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth); + + /** Set the world matrix for a spot-shaped decal. + * Convenience method that computes a world matrix for a circular decal + * centered at pos with given radius and optional rotation. + * \param pos 2D center position + * \param radius Radius of the spot + * \param angleInRadians Optional rotation angle + */ + void setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians = 0.f); + + /** Test if a 2D point is contained within this decal's projection area. + * Used by R2 editor tools for hit-testing. + * \param pos 2D point to test (world XY) + * \return true if the point falls within the unit-cube projection + */ + bool contains(const NLMISC::CVector2f &pos) const; + + /** Set the diffuse color applied to the decal. + * The RGB components tint the texture, alpha is a base opacity. + * \param diffuse RGBA diffuse color + */ + void setDiffuse(NLMISC::CRGBA diffuse) { _Diffuse = diffuse; } + + /// Get the current diffuse color. + NLMISC::CRGBA getDiffuse() const { return _Diffuse; } + + /** Set the emissive color added to the decal. + * Added on top of the texture × diffuse result. + * \param emissive RGBA emissive color + */ + void setEmissive(NLMISC::CRGBA emissive); + + /// Get the current emissive color. + NLMISC::CRGBA getEmissive() const { return _Emissive; } + + /** Set the bottom Z-blend region. + * Decal alpha fades from 0 at zMin to 1 at zMax (bottom edge). + * \param zMin Altitude below which the decal is fully transparent + * \param zMax Altitude above which bottom blend is fully opaque + */ + void setBottomBlend(float zMin, float zMax); + + /** Set the top Z-blend region. + * Decal alpha fades from 1 at zMin to 0 at zMax (top edge). + * \param zMin Altitude below which top blend is fully opaque + * \param zMax Altitude above which the decal is fully transparent + */ + void setTopBlend(float zMin, float zMax); + + /// Get bottom blend zMin. + float getBottomBlendZMin() const { return _BottomBlendZMin; } + /// Get bottom blend zMax. + float getBottomBlendZMax() const { return _BottomBlendZMax; } + /// Get top blend zMin. + float getTopBlendZMin() const { return _TopBlendZMin; } + /// Get top blend zMax. + float getTopBlendZMax() const { return _TopBlendZMax; } + + /** Get the world-to-UV matrix rows for the vertex program. + * Row 0 maps world X to U, Row 1 maps world Y to V. + * Set up during generateUVs() for the VP path. + */ + const CMatrix &getWorldToUVMatrix() const { return _WorldToUVMatrix; } + + /** Get the Matrix that transforms local coordinates to UV coordinates. + * Maps (x,y)=(0,0) to (u,v)=(0,1) and (x,y)=(0,1) to (u,v)=(0,0) + * in local decal space (unit cube). See PDF §4.5.3. + */ + static CMatrix getReverseUVMatrix() + { + CMatrix m; + m.setRot(CVector::I, -CVector::J, CVector::K); + m.setPos(CVector::J); + return m; + } + +private: + /// Creator function for scene model registration. + static CTransform *creator() { return new CDecal(); } + + /** Compute decal geometry: face selection, clipping, and UV generation. + * Called by getVertices() when the decal needs recomputation. + */ + void computeDecal(const bool useVertexProgram); + + /** Generate UV coordinates for the collected vertices. + * Uses the inverse world matrix to project back to unit-cube local space, + * then maps to UV sub-region defined by _UV1/_UV2. See PDF §4.5.3. + * Camera position is subtracted for numerical stability (§4.6.1). + */ + void generateUVs(); + + /** Compute per-vertex colors for the CPU fallback path. + * Applies diffuse color, distance attenuation, and bottom/top Z blending. + * \param distScale Linear distance attenuation scale factor + * \param distBias Linear distance attenuation bias + */ + void computeColors(float distScale, float distBias); + +private: + CMaterial _Mat; + uint32 _MaterialId; + + bool _Touched; + bool _FirstFrame; ///< True until the first frame has been traversed (matrices invalid on frame 0, see PDF §4.6.4) + uint32 _StableFrameCount; + + CVector _LastCamPos; + CVector _ClipCorners[4]; + + std::vector _Vertices; + std::vector _UVs; + std::vector _Colors; + bool _IsStatic; + uint8 _Priority; + bool _ClipDownFacing; + + CUV _UV1; + CUV _UV2; + CDecalContext _DecalContext; + + NLMISC::CRGBA _Diffuse; + NLMISC::CRGBA _Emissive; + float _BottomBlendZMin; + float _BottomBlendZMax; + float _TopBlendZMin; + float _TopBlendZMax; + + CMatrix _WorldToUVMatrix; + CMatrix _TextureMatrix; + bool _CustomUVMatrixEnabled; + CMatrix _CustomUVMatrix; + + /// Static mask texture for DecalClipMask mode (generated once, shared) + static NLMISC::CSmartPtr _MaskTexture; + static ITexture *getMaskTexture(); +}; + +}//NL3D +#endif diff --git a/nel/include/nel/3d/decal_manager.h b/nel/include/nel/3d/decal_manager.h new file mode 100644 index 0000000000..9f5c44b647 --- /dev/null +++ b/nel/include/nel/3d/decal_manager.h @@ -0,0 +1,182 @@ +/** \file decal_manager.h + * Batched decal rendering manager for NeL 3D. + * + * Collects decals sorted by material and renders them in batched draw calls + * using a fixed-size AGP volatile vertex buffer. See PDF §4.5.4 and §.6.3. + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef NL_DECAL_MANAGER_H +#define NL_DECAL_MANAGER_H + +#include "nel/3d/transform.h" + +#include "nel/3d/decal.h" +#include "nel/3d/material.h" +#include "nel/3d/vertex_buffer.h" +#include "nel/3d/vertex_program.h" +#include "nel/3d/driver.h" + + +namespace NL3D +{ + +class CScene; + + +/// Maximum number of vertices in the batching array buffer (see PDF §4.5.4). +/// When exceeded, the buffer is flushed and refilled. +const uint32 NL3D_DECAL_VB_MAX_VERTICES = 4096 * 3; + + +// *************************************************************************** +/** + * Vertex program for decal distance attenuation, bottom/top Z blending, + * and diffuse color modulation. + * + * Ported from the legacy CLegacyDecal system's DecalAttenuationVertexProgram. + * + * Constants: + * c[0-3]: ModelViewProjection matrix + * c[4]: WorldToUV row 0 (world X,Y,Z,W → U) + * c[5]: WorldToUV row 1 (world X,Y,Z,W → V) + * c[6]: Camera position (world space, relative to model origin) + * c[7]: DistScaleBias (x=scale, y=bias, z=0.0, w=1.0) + * c[8]: Diffuse color (RGB normalized to [0,1]) + * c[11]: BlendScale (x=bottomScale, y=bottomBias, z=topScale, w=topBias) + */ +class CVertexProgramDecalAttenuation : public CVertexProgram +{ +public: + struct CIdx + { + uint WorldToUV0; + uint WorldToUV1; + uint RefCamDist; + uint DistScaleBias; + uint Diffuse; + uint BlendScale; + }; + + CVertexProgramDecalAttenuation(); + ~CVertexProgramDecalAttenuation(); + virtual void buildInfo(); + inline const CIdx &idx() const { return m_Idx; } + +private: + CIdx m_Idx; +}; + + +// *************************************************************************** +/** + * Decal Manager: collects decals per material and renders them in batched draw calls. + * + * Each frame, CDecal::traverseRender() registers decals here. At flush time, + * the manager iterates per-material groups, fills a fixed-size AGP volatile + * vertex buffer (position + UV + color), and issues renderRawTriangles() calls. + * If the buffer overflows mid-decal, it is flushed and refilled (see PDF §.6.3). + * + * Supports a vertex program path (attenuation, Z blending, diffuse) and a CPU + * fallback path using per-vertex colors. + * + * \author Christopher Tarento + * \author Nevrax France + * \date 2007 + */ +class CDecalManager +{ + +public: + CDecalManager(); + ~CDecalManager(); + + /** Render all registered decals in batched draw calls. + * Iterates per-material, fills the VB, and renders. See PDF §.6.3. + * \param sc Owner scene (for driver access) + */ + void flush(CScene *sc); + + /** Register a decal for rendering this frame. + * \param decal The decal to add + * \param materialId Material ID for batching (decals with same ID are grouped) + */ + void addDecal(CDecal *decal, uint32 materialId); + + /** Register a material for use by decals. + * \param mat The material to register + * \return The material ID to use when creating decals + */ + uint32 registerMaterial(const CMaterial &mat); + + /// Clear all registered decals (called at start of each frame). + void clearAllDecals(); + + /** Set whether vertex programs should be used. + * \param b true to use vertex programs + */ + void setVertexProgram(const bool b) { _UseVertexProgram = b; } + + /** Set distance attenuation parameters (affects all decals). + * At distance d from camera: alpha *= d * scale + bias. + * Typically scale = -factor/maxDist, bias = factor. + * \param scale Distance scale factor + * \param bias Distance bias + */ + void setDistAttenuation(float scale, float bias) { _DistScale = scale; _DistBias = bias; } + + /// Get distance attenuation scale factor. + float getDistScale() const { return _DistScale; } + + /// Get distance attenuation bias. + float getDistBias() const { return _DistBias; } + +private: + /// A registered material with its ID + struct CRegisteredMaterial + { + CMaterial Mat; + uint32 Id; + }; + + /// Decals grouped by material ID, sorted by priority within each group + typedef std::map > TDecalMap; + TDecalMap _Decals; + + /// Registered materials by ID + std::vector _Materials; + uint32 _NextMaterialId; + + bool _UseVertexProgram; + float _DistScale; + float _DistBias; + + /// Fixed-size AGP volatile vertex buffer (Position + TexCoord0 + PrimaryColor) + CVertexBuffer _VB; + + /// The decal attenuation vertex program (shared instance) + NLMISC::CSmartPtr _VertexProgram; +}; + + + +}//NL3D +#endif diff --git a/nel/include/nel/3d/render_trav.h b/nel/include/nel/3d/render_trav.h index 91bbc1c00c..df9d837a1a 100644 --- a/nel/include/nel/3d/render_trav.h +++ b/nel/include/nel/3d/render_trav.h @@ -29,6 +29,7 @@ #include "nel/3d/light.h" #include "nel/3d/mesh_block_manager.h" #include "nel/3d/shadow_map_manager.h" +#include "nel/3d/decal_manager.h" #include "nel/3d/u_scene.h" #include "nel/3d/vertex_program.h" #include "nel/3d/transform.h" @@ -48,6 +49,7 @@ class CMaterial; class CTransform; class CLandscapeModel; +class CDecal; class CVertexStreamManager; class CWaterModel; @@ -247,9 +249,17 @@ class CRenderTrav : public CTravCameraScene CVertexStreamManager *getShadowMeshSkinManager() const {return _ShadowMeshSkinManager;} + /// get the decal manager + CDecalManager &getDecalManager() {return _DecalManager;} + const CDecalManager &getDecalManager() const {return _DecalManager;} + + // add a landscape. Special for CLandscapeModel::traverseRender(); void addRenderLandscape(CLandscapeModel *model); + /// Get list of landscape models registered this frame (for decal face collection). + const std::vector &getLandscapeRenderList() const { return _LandscapeRenderList; } + /// \name Temp Debug //@{ @@ -473,6 +483,8 @@ class CRenderTrav : public CTravCameraScene CShadowMapManager _ShadowMapManager; /// The SkinManager, but For Shadow rendering CVertexStreamManager *_ShadowMeshSkinManager; + /// The decal manager + CDecalManager _DecalManager; /** \name Special Landscape RenderList. diff --git a/nel/include/nel/3d/scene.h b/nel/include/nel/3d/scene.h index 4df37b4919..4ab3db3956 100644 --- a/nel/include/nel/3d/scene.h +++ b/nel/include/nel/3d/scene.h @@ -69,6 +69,8 @@ class CRootModel; class CVisualCollisionManager; class CTextureCube; class CWaterEnvMap; +class CDecal; +class CDecalManager; // *************************************************************************** /** diff --git a/nel/include/nel/3d/scene_user.h b/nel/include/nel/3d/scene_user.h index 92d2cba051..0aff4c1eb9 100644 --- a/nel/include/nel/3d/scene_user.h +++ b/nel/include/nel/3d/scene_user.h @@ -161,6 +161,9 @@ class CSceneUser : public UScene virtual UPointLight createPointLight(); virtual void deletePointLight(UPointLight &light); + virtual UDecal createDecal(); + virtual void deleteDecal(UDecal &decal); + //@} /// \name Animation gestion. diff --git a/nel/include/nel/3d/shadow_poly_receiver.h b/nel/include/nel/3d/shadow_poly_receiver.h index 5c94768492..e6aac8c9f1 100644 --- a/nel/include/nel/3d/shadow_poly_receiver.h +++ b/nel/include/nel/3d/shadow_poly_receiver.h @@ -30,6 +30,7 @@ namespace NL3D { class IDriver; class CMaterial; class CShadowMap; +class CDecalContext; // *************************************************************************** @@ -99,6 +100,14 @@ class CShadowPolyReceiver std::vector &destTris, bool colorUpfacingVertices); + /** Collect triangles for a projected decal. + * Selects triangles from the quad grid, clips per the decal context's planes, + * and outputs raw CVector triangles to CDecalContext::DestTris. + * \param cdc Decal context with clip planes, bounding box, and destination output. + * \param vertDelta Offset to add to vertices (for landscape tile positioning). + */ + void receiveDecal(CDecalContext &cdc, const CVector &vertDelta); + /** Use the triangles added for camera 3rd person collision * return a [0,1] value. 0 => collision at start. 1 => no collision. * \param testType is the type of intersection: simple ray, cylinder or cone diff --git a/nel/include/nel/3d/u_decal.h b/nel/include/nel/3d/u_decal.h new file mode 100644 index 0000000000..3971d4e433 --- /dev/null +++ b/nel/include/nel/3d/u_decal.h @@ -0,0 +1,108 @@ +/** \file u_decal.h + * User interface for projected texture decals. + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef NL_U_DECAL_H +#define NL_U_DECAL_H + +#include "nel/misc/types_nl.h" +#include "nel/misc/rgba.h" +#include "nel/misc/uv.h" +#include "nel/misc/matrix.h" +#include "nel/misc/vector_2f.h" +#include "nel/3d/u_transform.h" + + +namespace NL3D +{ + +class CDecal; + +class UDecal : public UTransform +{ +public: + + /// Constructors + UDecal() { _Object = NULL; } + UDecal(class CDecal *object) { _Object = (ITransformable*)object; } + /// Attach an object to this proxy + void attach(class CDecal *object) { _Object = (ITransformable*)object; } + /// Detach the object + void detach() { _Object = NULL; } + /// Return true if the proxy is empty() (not attached) + bool empty() const { return _Object == NULL; } + /// For advanced usage, get the internal object ptr + class CDecal *getObjectPtr() const { return (CDecal*)_Object; } + + /// Set the decal texture from a filename + void setTexture(const std::string &filename); + + /// Set the material ID for batching (from CDecalManager::registerMaterial) + void setMaterialId(uint32 id); + + /// Set the UV sub-region within a texture atlas + void setUVCoord(const NLMISC::CUV &uv1, const NLMISC::CUV &uv2); + + /// Set the clipping mode (0=None, 1=Mask, 2=Geometry) + void setClippingMode(uint mode); + + /// Mark this decal as static (only recomputed once) + void setStatic(bool isStatic); + + /// Set the diffuse color (RGB tints texture, A is base opacity) + void setDiffuse(NLMISC::CRGBA diffuse); + + /// Set the emissive color (added to texture × diffuse) + void setEmissive(NLMISC::CRGBA emissive); + + /// Set the bottom Z-blend region (fade from 0 at zMin to 1 at zMax) + void setBottomBlend(float zMin, float zMax); + + /// Set the top Z-blend region (fade from 1 at zMin to 0 at zMax) + void setTopBlend(float zMin, float zMax); + + /// Set the render priority (0 = highest/first, 7 = lowest/last) + void setPriority(uint8 priority); + + /// Set whether downward-facing surfaces should be clipped + void setClipDownFacing(bool clipDownFacing); + + /// Set a custom UV matrix (world → UV transform), replacing default UV generation + void setCustomUVMatrix(bool on, const NLMISC::CMatrix &matrix = NLMISC::CMatrix::Identity); + + /// Set the texture coordinate transform matrix + void setTextureMatrix(const NLMISC::CMatrix &matrix); + + /// Set the world matrix for an arrow-shaped decal + void setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth); + + /// Set the world matrix for a spot-shaped decal + void setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians = 0.f); + + /// Test if a 2D point is contained within this decal's projection area (for hit-testing) + bool contains(const NLMISC::CVector2f &pos) const; +}; + + +} //NL3D + +#endif diff --git a/nel/include/nel/3d/u_scene.h b/nel/include/nel/3d/u_scene.h index 42766badcf..71ba7fdecf 100644 --- a/nel/include/nel/3d/u_scene.h +++ b/nel/include/nel/3d/u_scene.h @@ -50,6 +50,7 @@ class UAnimationSet; class UPlayListManager; class UPointLight; class UWaterEnvMap; +class UDecal; // **************************************************************************** @@ -272,7 +273,12 @@ class UScene /// Delete a dynamic PointLight. virtual void deletePointLight(UPointLight &light)=0; + /// Create a dynamic Decal. + virtual UDecal createDecal()=0; + /// Delete a dynamic decal. + virtual void deleteDecal(UDecal &decal)=0; + //@} /// \name Animation Mgt. diff --git a/nel/include/nel/3d/visual_collision_manager.h b/nel/include/nel/3d/visual_collision_manager.h index 7b5b7e319b..8613764e00 100644 --- a/nel/include/nel/3d/visual_collision_manager.h +++ b/nel/include/nel/3d/visual_collision_manager.h @@ -35,6 +35,7 @@ class IDriver; class CShadowMap; class CShadowMapProjector; class CMaterial; +class CDecalContext; // *************************************************************************** @@ -150,6 +151,10 @@ class CVisualCollisionManager */ void removeMeshCollision(uint id); + /** Use the MeshInstance Collision to render Decal on them + * \param cdc Decal Context which contains useful informations for computing decals + */ + void receiveDecal(CDecalContext &cdc); /** Use the MeshInstance Collision to rended a ShadowMap on them. * NB: only the minimum faces touched by the shadowmap are rendered @@ -195,6 +200,9 @@ class CVisualCollisionManager /// receive a shadow map void receiveShadowMap(const CVisualCollisionMesh::CShadowContext &shadowContext); + + /// receive a decal + void receiveDecal(CDecalContext &cdc); }; // The map of Meshes Instance diff --git a/nel/include/nel/3d/visual_collision_mesh.h b/nel/include/nel/3d/visual_collision_mesh.h index d4532be757..e4937c5edd 100644 --- a/nel/include/nel/3d/visual_collision_mesh.h +++ b/nel/include/nel/3d/visual_collision_mesh.h @@ -33,6 +33,7 @@ class IDriver; class CShadowMap; class CShadowMapProjector; class CMaterial; +class CDecalContext; // *************************************************************************** @@ -60,10 +61,8 @@ class CVisualCollisionMesh : public NLMISC::CRefCount public: CShadowContext(CMaterial &mat, CIndexBuffer &ib, CShadowMapProjector &smp) : - ShadowMapProjector(smp), ShadowMaterial(mat), IndexBuffer(ib) + Driver(NULL), ShadowMap(NULL), ShadowMapProjector(smp), ShadowMaterial(mat), IndexBuffer(ib) { - Driver= NULL; - ShadowMap= NULL; } }; @@ -88,6 +87,9 @@ class CVisualCollisionMesh : public NLMISC::CRefCount /// compute the world bbox of an instance NLMISC::CAABBox computeWorldBBox(const NLMISC::CMatrix &instanceMatrix); + /// receive a decal. compute the triangles that intersect the decal + void receiveDecal(const NLMISC::CMatrix &instanceMatrix, CDecalContext &decalContext); + /// receive a shadowMap. render in driver the triangles that intersect the shadow void receiveShadowMap(const NLMISC::CMatrix &instanceMatrix, const CShadowContext &shadowContext); diff --git a/nel/src/3d/decal.cpp b/nel/src/3d/decal.cpp new file mode 100644 index 0000000000..d646fe981f --- /dev/null +++ b/nel/src/3d/decal.cpp @@ -0,0 +1,540 @@ +/** \file decal.cpp + * Projected texture decal system for NeL 3D. + * + * Based on the design from the intern report by Christopher Tarento (2007). + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "std3d.h" +#include "nel/3d/decal.h" + +#include "nel/3d/texture_file.h" +#include "nel/3d/texture_mem.h" +#include "nel/3d/scene.h" +#include "nel/3d/driver.h" +#include "nel/3d/clip_trav.h" +#include "nel/3d/visual_collision_manager.h" +#include "nel/3d/render_trav.h" +#include "nel/3d/landscape_model.h" + +using namespace std; +using namespace NL3D; +using namespace NLMISC; + + +// *************************************************************************** +CDecalContext::CDecalContext() : ClipMode(DecalClipGeometry), DestTris(NULL), ClipDownFacing(false) {} + +// *************************************************************************** +// Static mask texture (shared across all decals) +NLMISC::CSmartPtr CDecal::_MaskTexture; + + +// *************************************************************************** +CDecal::CDecal() : +_MaterialId(0), +_Touched(true), +_FirstFrame(true), +_StableFrameCount(0), +_IsStatic(false), +_Priority(0), +_ClipDownFacing(false), +_UV1(CUV(0, 0)), +_UV2(CUV(1, 1)), +_Diffuse(CRGBA::White), +_Emissive(CRGBA::Black), +_BottomBlendZMin(-1e10f), +_BottomBlendZMax(-1e10f), +_TopBlendZMin(1e10f), +_TopBlendZMax(1e10f), +_CustomUVMatrixEnabled(false) +{ +setOpacity(true); +setTransparency(false); +setIsRenderable(true); + +// Material setup: unlit, alpha-blended, double-sided, no z-write, with z-bias +_Mat.initUnlit(); +_Mat.setBlend(true); +_Mat.setSrcBlend(CMaterial::srcalpha); +_Mat.setDstBlend(CMaterial::invsrcalpha); +_Mat.setZWrite(false); +_Mat.setDoubleSided(true); +_Mat.setZBias(-0.06f); +_Mat.setAlphaTest(true); +_Mat.setAlphaTestThreshold(1.f / 255.f); + +// Stage 0: diffuse color applied to texture +// RGB = Texture * Diffuse, Alpha = Diffuse * Texture +_Mat.texEnvOpRGB(0, CMaterial::Modulate); +_Mat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor); +_Mat.texEnvArg1RGB(0, CMaterial::Diffuse, CMaterial::SrcColor); +_Mat.texEnvOpAlpha(0, CMaterial::Modulate); +_Mat.texEnvArg0Alpha(0, CMaterial::Diffuse, CMaterial::SrcAlpha); +_Mat.texEnvArg1Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha); + +// Stage 1: add emissive color +// RGB = Previous + Constant, Alpha = Previous * Constant +_Mat.texEnvOpRGB(1, CMaterial::Add); +_Mat.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor); +_Mat.texEnvArg1RGB(1, CMaterial::Constant, CMaterial::SrcColor); +_Mat.texEnvOpAlpha(1, CMaterial::Modulate); +_Mat.texEnvArg0Alpha(1, CMaterial::Previous, CMaterial::SrcAlpha); +_Mat.texEnvArg1Alpha(1, CMaterial::Constant, CMaterial::SrcAlpha); + +setEmissive(CRGBA::Black); + +// Default clipping mode: geometry clipping (best fillrate, see PDF 4.5.2) +_DecalContext.ClipMode = DecalClipGeometry; +} + + +// *************************************************************************** +void CDecal::initModel() +{ +_LastCamPos = getOwnerScene()->getCam()->getMatrix().getPos(); +} + + +// *************************************************************************** +CDecal::~CDecal() +{ +} + + +// *************************************************************************** +void CDecal::registerBasic() +{ +CScene::registerModel(DecalId, TransformId, CDecal::creator); +} + + +// *************************************************************************** +void CDecal::setTexture(const std::string &filename) +{ +CTextureFile *tex = new CTextureFile(filename); +tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapLinear); +tex->setWrapS(ITexture::Clamp); +tex->setWrapT(ITexture::Clamp); +_Mat.setTexture(0, tex); +// Stage 1 also needs the texture for the emissive add operation to work correctly +_Mat.setTexture(1, tex); +} + + +// *************************************************************************** +void CDecal::setEmissive(NLMISC::CRGBA emissive) +{ +_Emissive = emissive; +// Set the stage 1 constant color to the emissive value +_Mat.texConstantColor(1, CRGBA(emissive.R, emissive.G, emissive.B, 255)); +} + + +// *************************************************************************** +void CDecal::setBottomBlend(float zMin, float zMax) +{ +if (zMin > zMax) std::swap(zMin, zMax); +_BottomBlendZMin = zMin; +_BottomBlendZMax = zMax; +} + + +// *************************************************************************** +void CDecal::setTopBlend(float zMin, float zMax) +{ +if (zMin > zMax) std::swap(zMin, zMax); +_TopBlendZMin = zMin; +_TopBlendZMax = zMax; +} + + +// *************************************************************************** +// Clip method: bounding sphere vs frustum test (see PDF .6.1) +bool CDecal::clip() +{ +CScene *scene = getOwnerScene(); +CClipTrav &clipTrav = scene->getClipTrav(); + +// Compute bounding sphere from decal's world matrix +// The decal is a unit cube [0,1]^3, so center is at (0.5, 0.5, 0.5) in local space +CVector localCenter(0.5f, 0.5f, 0.5f); +CVector worldCenter = getWorldMatrix() * localCenter; + +// Radius: half-diagonal of the unit cube, scaled by the largest scale factor +// For a unit cube, half-diagonal = sqrt(3)/2 ~ 0.866 +float scaleI = (getWorldMatrix().getI()).norm(); +float scaleJ = (getWorldMatrix().getJ()).norm(); +float scaleK = (getWorldMatrix().getK()).norm(); +float maxScale = std::max(scaleI, std::max(scaleJ, scaleK)); +float radius = 0.866f * maxScale; + +// Test against camera frustum planes +const std::vector &pyramid = clipTrav.WorldPyramid; +for (uint i = 0; i < pyramid.size(); ++i) +{ +float d = pyramid[i] * worldCenter; +if (d > radius) +{ +return false; +} +} + +return true; +} + + +// *************************************************************************** +// Render traversal: just register with the decal manager for batched rendering +void CDecal::traverseRender() +{ +getOwnerScene()->getRenderTrav().getDecalManager().addDecal(this, _MaterialId); +} + + +// *************************************************************************** +std::vector &CDecal::getVertices(const bool useVertexProgram) +{ +const NLMISC::CVector &camPos = getOwnerScene()->getCam()->getMatrix().getPos(); + +// First-frame skip: matrices are incorrect on the first traversal (PDF §4.6.4). +// Return empty vertices and defer computation to the next frame. +if (_FirstFrame) +{ + _FirstFrame = false; + _LastCamPos = camPos; + _Touched = true; + _Vertices.clear(); + _UVs.clear(); + _Colors.clear(); + return _Vertices; +} + +if (_IsStatic) +{ +// Static decal: only recompute on first touch. +// After that, use frame-count heuristic based on camera movement (4.5.4). +if (_Touched) +{ +_LastCamPos = camPos; +computeDecal(useVertexProgram); +_Touched = false; +_StableFrameCount = 0; +} +} +else +{ +// Dynamic decal: recompute when camera moves significantly (4.6.1). +// Use visibility distance as threshold for recalculation. +if ((camPos - _LastCamPos).norm() >= 4.f) +{ +_Touched = true; +} + +if (_Touched) +{ +_LastCamPos = camPos; +computeDecal(useVertexProgram); +_Touched = false; +_StableFrameCount = 0; +} +else +{ +// Increment stable frame count. If a dynamic decal has been stable +// for many frames, it effectively becomes static (4.5.4 heuristic). +_StableFrameCount++; +} +} + +return _Vertices; +} + + +// *************************************************************************** +// Face selection and clipping (see PDF .6.2 and 4.5.1/4.5.2) +void CDecal::computeDecal(const bool useVertexProgram) +{ +CScene *sc = getOwnerScene(); + +CVisualCollisionManager *vcm = sc->getVisualCollisionManagerForShadow(); +if (!vcm) +{ +nlwarning("CDecal::computeDecal: VisualCollisionManager not available"); +return; +} + +CDecalContext &context = _DecalContext; + +// Build clip planes from the unit cube corners transformed to world space +float decalSize = 1.0f; +_ClipCorners[0] = getWorldMatrix() * (CVector(0.f, 1.f, 0.f) * decalSize); +_ClipCorners[1] = getWorldMatrix() * (CVector(1.f, 1.f, 0.f) * decalSize); +_ClipCorners[2] = getWorldMatrix() * (CVector(1.f, 0.f, 0.f) * decalSize); +_ClipCorners[3] = getWorldMatrix() * (CVector(0.f, 0.f, 0.f) * decalSize); + +// Build 4 side clip planes from the corners (4.5.1) +context.WorldClipPlanes.resize(4); +context.WorldBBox.setMinMax( +getWorldMatrix() * (CVector(0.f, 0.f, 0.f) * decalSize), +getWorldMatrix() * (CVector(1.f, 1.f, 1.f) * decalSize)); + +for (uint i = 0; i < 4; ++i) +{ +context.WorldClipPlanes[i].make( +_ClipCorners[i], +_ClipCorners[(i + 1) & 3], +_ClipCorners[i] + (_ClipCorners[(i + 1) & 3] - _ClipCorners[i]).norm() * CVector::K); +context.WorldClipPlanes[i].invert(); +} + +context.WorldMatrix = getWorldMatrix(); +context.ClipDownFacing = _ClipDownFacing; + +// Clear and collect triangles via visual collision (objects/meshes) +_Vertices.clear(); +context.DestTris = &_Vertices; +vcm->receiveDecal(context); + +// Also collect triangles from landscape's shadow poly receiver (terrain) +CRenderTrav &renderTrav = sc->getRenderTrav(); +const std::vector &landscapes = renderTrav.getLandscapeRenderList(); +for (uint i = 0; i < landscapes.size(); ++i) +{ +CLandscapeModel *lm = landscapes[i]; +if (!lm) continue; +// Shadow poly receiver stores vertices in world space (EndPos from tessellation). +// We render with Identity model matrix, so no offset needed. +lm->Landscape.getShadowPolyReceiver().receiveDecal(context, CVector::Null); +} + +// Generate UV coordinates from collected vertices +generateUVs(); + +// Always compute per-vertex colors on CPU for batched rendering. +// This allows the manager to batch decals without per-decal VP constant changes. +CDecalManager &mgr = sc->getRenderTrav().getDecalManager(); +computeColors(mgr.getDistScale(), mgr.getDistBias()); +} + + +// *************************************************************************** +// UV coordinate generation (see PDF 4.5.3) +// Uses inverse world matrix to project world-space vertices back to unit-cube local space. +// Supports custom UV matrix and texture matrix overrides. +// Also builds the worldToUV matrix for the VP path. +void CDecal::generateUVs() +{ +_UVs.resize(_Vertices.size()); + +if (_Vertices.empty()) +return; + +// Compute worldToUV matrix: maps world position to [0,1] UV in local decal space +CMatrix invWorld = getWorldMatrix().inverted(); + +if (_CustomUVMatrixEnabled) +{ + // Custom UV matrix overrides the entire UV generation pipeline + _WorldToUVMatrix = _CustomUVMatrix; +} +else +{ + // Default: texture matrix × reverse UV matrix × inverse world + CMatrix reverseUV = getReverseUVMatrix(); + _WorldToUVMatrix = _TextureMatrix * reverseUV * invWorld; +} + +// Use the worldToUV matrix to generate UVs, matching the VP path. +// Row 0 of the matrix gives U, Row 1 gives V. +const float *m = _WorldToUVMatrix.get(); +for (uint i = 0; i < _Vertices.size(); ++i) +{ + const CVector &vtx = _Vertices[i]; + // DP4 equivalent: dot product of matrix row with (vx, vy, vz, 1) + float u = m[0] * vtx.x + m[4] * vtx.y + m[8] * vtx.z + m[12]; + float v = m[1] * vtx.x + m[5] * vtx.y + m[9] * vtx.z + m[13]; + + // Apply UV sub-region mapping (for texture atlases) + _UVs[i].U = _UV1.U + u * (_UV2.U - _UV1.U); + _UVs[i].V = _UV1.V + v * (_UV2.V - _UV1.V); +} +} + + +// *************************************************************************** +// Compute per-vertex colors for CPU fallback path +// Applies diffuse color, distance attenuation, and bottom/top Z blending. +void CDecal::computeColors(float distScale, float distBias) +{ +_Colors.resize(_Vertices.size()); + +if (_Vertices.empty()) +return; + +const CVector camPos = getOwnerScene()->getCam()->getMatrix().getPos(); + +float bottomBlendScale = 1.f / NLMISC::favoid0(_BottomBlendZMax - _BottomBlendZMin); +float topBlendScale = 1.f / NLMISC::favoid0(_TopBlendZMin - _TopBlendZMax); + +for (uint i = 0; i < _Vertices.size(); ++i) +{ +const CVector &v = _Vertices[i]; + +// Distance attenuation +float dist = (camPos - v).norm(); +float intensity = dist * distScale + distBias; +clamp(intensity, 0.f, 1.f); + +// Bottom blend +float bottomBlend = (v.z - _BottomBlendZMin) * bottomBlendScale; +clamp(bottomBlend, 0.f, 1.f); +intensity *= bottomBlend; + +// Top blend +float topBlend = (v.z - _TopBlendZMax) * topBlendScale; +clamp(topBlend, 0.f, 1.f); +intensity *= topBlend; + +// Apply to diffuse color +_Colors[i].R = _Diffuse.R; +_Colors[i].G = _Diffuse.G; +_Colors[i].B = _Diffuse.B; +_Colors[i].A = (uint8)((float)_Diffuse.A * intensity); +} +} + + +// *************************************************************************** +void CDecal::setUVCoord(const CUV uv1, const CUV uv2) +{ +_UV1 = uv1; +_UV2 = uv2; +_Touched = true; + +// Mipmap limiting for texture atlases (PDF §4.6.2): +// When using a sub-region, mipmaps can bleed into neighboring portions. +// Disable mipmaps on the texture to prevent this. +ITexture *tex = _Mat.getTexture(0); +if (tex) +{ + bool isSubRegion = (fabsf(uv1.U) > 1e-6f || fabsf(uv1.V) > 1e-6f || fabsf(uv2.U - 1.f) > 1e-6f || fabsf(uv2.V - 1.f) > 1e-6f); + if (isSubRegion) + { + tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); + } + else + { + tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapLinear); + } +} +} + + +// *************************************************************************** +void CDecal::setCustomUVMatrix(bool on, const CMatrix &matrix) +{ +_CustomUVMatrixEnabled = on; +_CustomUVMatrix = matrix; +_Touched = true; +} + + +// *************************************************************************** +void CDecal::setTextureMatrix(const CMatrix &matrix) +{ +_TextureMatrix = matrix; +_Touched = true; +} + + +// *************************************************************************** +void CDecal::setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth) +{ +CMatrix matrix; +CVector I = CVector(end.x, end.y, 0.f) - CVector(start.x, start.y, 0.f); +CVector J = 2.f * halfWidth * CVector::K ^ I.normed(); +matrix.setRot(I, J, CVector::K); +matrix.setPos(CVector(start.x, start.y, 0.f) - 0.5f * J); +setMatrix(matrix); +_Touched = true; +} + + +// *************************************************************************** +void CDecal::setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians) +{ +CMatrix matrix; +matrix.rotateZ(angleInRadians); +matrix.setScale(2.f * radius); +matrix.setPos(CVector(pos.x - radius, pos.y - radius, 0.f)); +setMatrix(matrix); +_Touched = true; +} + + +// *************************************************************************** +ITexture *CDecal::getMaskTexture() +{ +if (_MaskTexture != NULL) + return _MaskTexture; + +// Generate a 4×4 RGBA texture: opaque white in the 2×2 center, transparent black at edges +const uint32 maskSize = 4; +const uint32 maskCenterMin = 1; // inclusive: center region starts at pixel 1 +const uint32 maskCenterMax = 2; // inclusive: center region ends at pixel 2 +uint32 dataSize = maskSize * maskSize * 4; // RGBA +uint8 *data = new uint8[dataSize]; +memset(data, 0, dataSize); +for (uint y = 0; y < maskSize; ++y) +{ + for (uint x = 0; x < maskSize; ++x) + { + uint idx = (y * maskSize + x) * 4; + // Center pixels are opaque white + if (x >= maskCenterMin && x <= maskCenterMax && y >= maskCenterMin && y <= maskCenterMax) + { + data[idx + 0] = 255; // R + data[idx + 1] = 255; // G + data[idx + 2] = 255; // B + data[idx + 3] = 255; // A + } + // Edge pixels are transparent (already 0) + } +} + +CTextureMem *tex = new CTextureMem(data, dataSize, true, false, maskSize, maskSize, CBitmap::RGBA); +tex->setWrapS(ITexture::Clamp); +tex->setWrapT(ITexture::Clamp); +tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); +tex->setUploadFormat(ITexture::RGBA8888); +_MaskTexture = tex; +return _MaskTexture; +} + + +// *************************************************************************** +bool CDecal::contains(const NLMISC::CVector2f &pos) const +{ + CMatrix invMat = getWorldMatrix(); + invMat.invert(); + CVector posIn = invMat * CVector(pos.x, pos.y, 0.f); + return posIn.x >= 0.f && posIn.x <= 1.f && posIn.y >= 0.f && posIn.y <= 1.f; +} diff --git a/nel/src/3d/decal_manager.cpp b/nel/src/3d/decal_manager.cpp new file mode 100644 index 0000000000..274ab56aec --- /dev/null +++ b/nel/src/3d/decal_manager.cpp @@ -0,0 +1,299 @@ +/** \file decal_manager.cpp + * Batched decal rendering manager for NeL 3D. + * + * Implements the rendering pseudocode from the intern report (§.6.3). + * Includes the vertex program for distance attenuation, Z blending, + * and diffuse color (ported from the legacy CLegacyDecal system). + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "std3d.h" +#include "nel/3d/decal_manager.h" +#include "nel/3d/scene.h" + +#include + +using namespace std; +using namespace NLMISC; +using namespace NL3D; + + +// *************************************************************************** +// Comparator for sorting decals by priority (lower priority value = rendered first) +static bool decalPriorityCompare(const CDecal *a, const CDecal *b) +{ + return a->getPriority() < b->getPriority(); +} + + +// *************************************************************************** +// Vertex program assembly code for decal attenuation (ported from legacy system) +// Constants: +// c[0-3]: ModelViewProjection matrix +// c[4]: WorldToUV row 0 (→ tex U) +// c[5]: WorldToUV row 1 (→ tex V) +// c[6]: Camera position (relative to model origin) +// c[7]: DistScaleBias (x=scale, y=bias, z=0.0, w=1.0) +// c[8]: Diffuse color (RGB in [0,1]) +// c[11]: BlendScale (x=bottomScale, y=bottomBias, z=topScale, w=topBias) +static const char *DecalAttenuationVertexProgramCode = +"!!VP1.0\n\ + DP4 o[HPOS].x, c[0], v[0]; #transform vertex in view space\n\ + DP4 o[HPOS].y, c[1], v[0];\n\ + DP4 o[HPOS].z, c[2], v[0];\n\ + DP4 o[HPOS].w, c[3], v[0];\n\ + # transform texcoord 0\n\ + DP4 o[TEX0].x, c[4], v[0];\n\ + DP4 o[TEX0].y, c[5], v[0];\n\ + #compute distance from camera\n\ + ADD R0, v[0], -c[6];\n\ + DP3 R0.x, R0, R0;\n\ + RSQ R0.x, R0.x;\n\ + RCP R0.x, R0.x;\n\ + MUL o[COL0].xyz, c[8], v[3];\n\ + #compute attenuation with distance\n\ + MAD R0.w, R0.x, c[7].x, c[7].y;\n\ + # clamp in [0, 1]\n\ + MIN R0.w, R0.w, c[7].w;\n\ + MAX R0.w, R0.w, c[7].z;\n\ + #compute bottom blend\n\ + MAD R1.x, v[0].z, c[11].x, c[11].y;\n\ + MIN R1.x, R1.x, c[7].w;\n\ + MAX R1.x, R1.x, c[7].z;\n\ + MUL R0.w, R1.x, R0.w;\n\ + #compute top blend\n\ + MAD R1.x, v[0].z, c[11].z, c[11].w;\n\ + MIN R1.x, R1.x, c[7].w;\n\ + MAX R1.x, R1.x, c[7].z;\n\ + MUL R0.w, R1.x, R0.w;\n\ + #apply vertex alpha\n\ + MUL o[COL0].w, v[3].w, R0.w;\n\ + END \n"; + + +// *************************************************************************** +CVertexProgramDecalAttenuation::CVertexProgramDecalAttenuation() +{ + CSource *source = new CSource(); + source->Profile = nelvp; + source->DisplayName = "nelvp/DecalAttenuation"; + source->setSourcePtr(DecalAttenuationVertexProgramCode); + source->ParamIndices["modelViewProjection"] = 0; + source->ParamIndices["worldToUV0"] = 4; + source->ParamIndices["worldToUV1"] = 5; + source->ParamIndices["refCamDist"] = 6; + source->ParamIndices["distScaleBias"] = 7; + source->ParamIndices["diffuse"] = 8; + source->ParamIndices["blendScale"] = 11; + addSource(source); +} + + +// *************************************************************************** +CVertexProgramDecalAttenuation::~CVertexProgramDecalAttenuation() +{ +} + + +// *************************************************************************** +void CVertexProgramDecalAttenuation::buildInfo() +{ + m_Idx.WorldToUV0 = getUniformIndex("worldToUV0"); + nlassert(m_Idx.WorldToUV0 != std::numeric_limits::max()); + m_Idx.WorldToUV1 = getUniformIndex("worldToUV1"); + nlassert(m_Idx.WorldToUV1 != std::numeric_limits::max()); + m_Idx.RefCamDist = getUniformIndex("refCamDist"); + nlassert(m_Idx.RefCamDist != std::numeric_limits::max()); + m_Idx.DistScaleBias = getUniformIndex("distScaleBias"); + nlassert(m_Idx.DistScaleBias != std::numeric_limits::max()); + m_Idx.Diffuse = getUniformIndex("diffuse"); + nlassert(m_Idx.Diffuse != std::numeric_limits::max()); + m_Idx.BlendScale = getUniformIndex("blendScale"); + nlassert(m_Idx.BlendScale != std::numeric_limits::max()); +} + + +// *************************************************************************** +CDecalManager::CDecalManager() : + _NextMaterialId(0), + _UseVertexProgram(false), + _DistScale(0.f), + _DistBias(1.f) +{ + // Fixed-size AGP Volatile vertex buffer with Position + TexCoord0 + PrimaryColor (see PDF §4.5.4). + // UV coordinates are precomputed on CPU by CDecal::generateUVs() and written to TexCoord0. + // Per-vertex colors are precomputed by CDecal::computeColors(). + // This avoids per-decal VP constant changes and enables true batching by texture. + _VB.setPreferredMemory(CVertexBuffer::AGPVolatile, true); + _VB.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::PrimaryColorFlag); + _VB.setNumVertices(NL3D_DECAL_VB_MAX_VERTICES); + + // Route texture stage 1 to read from TexCoord0 (same as stage 0). + // The material uses 2 stages but we only have one UV channel in the VB. + _VB.setUVRouting(1, 0); + + // Create the vertex program instance (retained for potential future use) + _VertexProgram = new CVertexProgramDecalAttenuation(); +} + + +// *************************************************************************** +CDecalManager::~CDecalManager() +{ +} + + +// *************************************************************************** +void CDecalManager::clearAllDecals() +{ + _Decals.clear(); +} + + +// *************************************************************************** +void CDecalManager::addDecal(CDecal *decal, uint32 materialId) +{ + _Decals[materialId].push_back(decal); +} + + +// *************************************************************************** +uint32 CDecalManager::registerMaterial(const CMaterial &mat) +{ + CRegisteredMaterial rm; + rm.Mat = mat; + rm.Id = _NextMaterialId; + _Materials.push_back(rm); + return _NextMaterialId++; +} + + +// *************************************************************************** +// Rendering: implements the pseudocode from PDF §.6.3 +// +// Per-vertex colors are precomputed on the CPU by CDecal::computeColors(). +// UV coordinates are precomputed on the CPU by CDecal::generateUVs() and +// written into TexCoord0. This avoids per-decal VP constant updates and +// enables true batching: a draw call is only needed when the texture +// pointer changes or the VB overflows. +void CDecalManager::flush(CScene *sc) +{ + if (_Decals.empty()) + return; + + IDriver *drv = sc->getRenderTrav().getDriver(); + + drv->activeVertexProgram(NULL); + drv->activeVertexBuffer(_VB); + drv->setupModelMatrix(CMatrix::Identity); + + // Iterate over each material group + TDecalMap::iterator matIt = _Decals.begin(); + TDecalMap::iterator matEnd = _Decals.end(); + + for (; matIt != matEnd; ++matIt) + { + std::vector &decals = matIt->second; + + if (decals.empty()) + continue; + + // Sort decals by priority within this material group (lower priority first) + std::sort(decals.begin(), decals.end(), decalPriorityCompare); + + // Track current texture and material for batching + ITexture *curTex = NULL; + CMaterial *batchMat = NULL; + uint32 vbOffset = 0; + + for (uint d = 0; d < decals.size(); ++d) + { + CDecal *decal = decals[d]; + + // Get this decal's precomputed vertices, UVs and colors + std::vector &verts = decal->getVertices(false); + const std::vector &uvs = decal->getUVs(); + const std::vector &colors = decal->getColors(); + + if (verts.empty()) + continue; + + CMaterial &mat = decal->getMaterial(); + ITexture *tex = mat.getTexture(0); + + // Flush on texture change + if (tex != curTex && vbOffset > 0) + { + nlassert(vbOffset % 3 == 0); + drv->renderRawTriangles(*batchMat, 0, vbOffset / 3); + vbOffset = 0; + } + curTex = tex; + batchMat = &mat; + + uint32 length = (uint32)verts.size(); + uint32 srcOffset = 0; + bool hasUVs = (uvs.size() == verts.size()); + bool hasColors = (colors.size() == verts.size()); + + while (srcOffset < length) + { + uint32 remaining = length - srcOffset; + uint32 space = NL3D_DECAL_VB_MAX_VERTICES - vbOffset; + + // Flush if VB is full + if (space == 0) + { + nlassert(vbOffset % 3 == 0); + drv->renderRawTriangles(mat, 0, vbOffset / 3); + vbOffset = 0; + space = NL3D_DECAL_VB_MAX_VERTICES; + } + + uint32 batch = std::min(remaining, space); + + { + CVertexBufferReadWrite vba; + _VB.lock(vba); + for (uint32 i = 0; i < batch; ++i) + { + uint32 vi = vbOffset + i; + uint32 si = srcOffset + i; + *vba.getVertexCoordPointer(vi) = verts[si]; + vba.setTexCoord(vi, 0, hasUVs ? uvs[si] : CUV(0, 0)); + vba.setColor(vi, hasColors ? colors[si] : CRGBA::White); + } + } + + vbOffset += batch; + srcOffset += batch; + } + } + + // Flush remaining vertices for this material group + if (vbOffset > 0 && batchMat) + { + nlassert(vbOffset % 3 == 0); + drv->renderRawTriangles(*batchMat, 0, vbOffset / 3); + vbOffset = 0; + } + } +} diff --git a/nel/src/3d/render_trav.cpp b/nel/src/3d/render_trav.cpp index 74fccc3a07..0074572e2c 100644 --- a/nel/src/3d/render_trav.cpp +++ b/nel/src/3d/render_trav.cpp @@ -238,6 +238,10 @@ void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender, bool // Clear any landscape clearRenderLandscapeList(); + // Clear any decal + _DecalManager.clearAllDecals(); + + // Start LodCharacter Manager render. CLodCharacterManager *clodMngr= Scene->getLodCharacterManager(); if(clodMngr) @@ -371,6 +375,10 @@ void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender, bool Scene->getLandscapePolyDrawingCallback()->endPolyDrawing(); } + // Render the decals + _DecalManager.flush(Scene); + + // Profile this frame? if(Scene->isNextRenderProfile()) { diff --git a/nel/src/3d/scene.cpp b/nel/src/3d/scene.cpp index b6dd550b1e..c54c5c51ab 100644 --- a/nel/src/3d/scene.cpp +++ b/nel/src/3d/scene.cpp @@ -55,6 +55,7 @@ #include "nel/3d/async_texture_manager.h" #include "nel/3d/water_env_map.h" #include "nel/3d/skeleton_spawn_script.h" +#include "nel/3d/decal.h" #include @@ -121,6 +122,7 @@ void CScene::registerBasics() CPointLightModel::registerBasic(); CSegRemanence::registerBasic(); CQuadGridClipManager::registerBasic(); + CDecal::registerBasic(); } diff --git a/nel/src/3d/scene_user.cpp b/nel/src/3d/scene_user.cpp index 4eed212a46..4930ce9a28 100644 --- a/nel/src/3d/scene_user.cpp +++ b/nel/src/3d/scene_user.cpp @@ -23,8 +23,10 @@ #include "nel/3d/u_instance.h" #include "nel/3d/u_camera.h" #include "nel/3d/u_skeleton.h" +#include "nel/3d/u_decal.h" #include "nel/3d/scene_user.h" #include "nel/3d/skeleton_model.h" +#include "nel/3d/decal.h" #include "nel/3d/coarse_mesh_manager.h" #include "nel/3d/point_light_model.h" #include "nel/3d/lod_character_manager.h" @@ -48,6 +50,7 @@ H_AUTO_DECL( NL3D_UI_Scene ) H_AUTO_DECL( NL3D_Misc_Scene_CreateDel_Element ) H_AUTO_DECL( NL3D_CreateOrLoad_Instance ) H_AUTO_DECL( NL3D_CreateOrLoad_Skeleton ) +H_AUTO_DECL( NL3D_CreateOrLoad_Decal ) H_AUTO_DECL( NL3D_Load_CLodOrCoarseMesh ) H_AUTO_DECL( NL3D_Load_AsyncIG ) @@ -55,6 +58,7 @@ H_AUTO_DECL( NL3D_Load_AsyncIG ) #define NL3D_HAUTO_ELT_SCENE H_AUTO_USE( NL3D_Misc_Scene_CreateDel_Element ) #define NL3D_HAUTO_CREATE_INSTANCE H_AUTO_USE( NL3D_CreateOrLoad_Instance ) #define NL3D_HAUTO_CREATE_SKELETON H_AUTO_USE( NL3D_CreateOrLoad_Skeleton ) +#define NL3D_HAUTO_CREATE_DECAL H_AUTO_USE( NL3D_CreateOrLoad_Decal ) #define NL3D_HAUTO_LOAD_LOD H_AUTO_USE( NL3D_Load_CLodOrCoarseMesh ) #define NL3D_HAUTO_ASYNC_IG H_AUTO_USE( NL3D_Load_AsyncIG ) @@ -331,6 +335,35 @@ void CSceneUser::deletePointLight(UPointLight &light) light.detach (); } +// *************************************************************************** + +UDecal CSceneUser::createDecal() +{ + NL3D_HAUTO_CREATE_DECAL; + + CTransform *t = _Scene.createModel(DecalId); + if (t) + { + CDecal *decal= safe_cast (t); + return UDecal(decal); + } + else + { + return UDecal(); + } +} + +// *************************************************************************** + +void CSceneUser::deleteDecal(UDecal &decal) +{ + NL3D_HAUTO_ELT_SCENE; + + // The component is auto added/deleted to _Scene in ctor/dtor. + _Scene.deleteModel(decal.getObjectPtr()); + decal.detach (); +} + // *************************************************************************** void CSceneUser::setGlobalWindPower(float gwp) diff --git a/nel/src/3d/shadow_poly_receiver.cpp b/nel/src/3d/shadow_poly_receiver.cpp index 7091310f70..db3601e061 100644 --- a/nel/src/3d/shadow_poly_receiver.cpp +++ b/nel/src/3d/shadow_poly_receiver.cpp @@ -20,6 +20,7 @@ #include "nel/misc/polygon.h" #include "nel/3d/shadow_poly_receiver.h" #include "nel/3d/shadow_map.h" +#include "nel/3d/decal.h" #include "nel/3d/driver.h" #include "nel/3d/camera_col.h" @@ -542,6 +543,121 @@ void CShadowPolyReceiver::renderWithPolyClip(IDriver *drv, CMaterial &shadowMa renderSelection(drv, shadowMat, shadowMap, casterPos, vertDelta); } +// *************************************************************************** +void CShadowPolyReceiver::receiveDecal(CDecalContext &cdc, const CVector &vertDelta) +{ + // Select triangles from the quad grid using the decal's bounding box + _TriangleGrid.select(cdc.WorldBBox.getMin(), cdc.WorldBBox.getMax()); + if (_TriangleGrid.begin() == _TriangleGrid.end()) return; + + nlassert(cdc.DestTris != NULL); + + uint i, j; + + // Reset vertex flags for selected triangles + TTriangleGrid::CIterator it; + for (it = _TriangleGrid.begin(); it != _TriangleGrid.end(); it++) + { + CTriangleId &triId = *it; + for (i = 0; i < 3; i++) + { + _Vertices[triId.Vertex[i]].Flags = 0; + } + } + + // Clip planes from decal context (max NL3D_SPR_NUM_CLIP_PLANE) + uint numClipPlanes = std::min((uint)cdc.WorldClipPlanes.size(), (uint)NL3D_SPR_NUM_CLIP_PLANE); + + // Collect visible triangles (those not fully clipped by all planes) + static std::vector visibleTris; + visibleTris.clear(); + + for (it = _TriangleGrid.begin(); it != _TriangleGrid.end(); it++) + { + CTriangleId &triId = *it; + uint triFlag = NL3D_SPR_NUM_CLIP_PLANE_MASK; + + CVectorId *vid[3] = { + &_Vertices[triId.Vertex[0]], + &_Vertices[triId.Vertex[1]], + &_Vertices[triId.Vertex[2]] + }; + + for (i = 0; i < 3; i++) + { + if (!vid[i]->Flags) + { + for (j = 0; j < numClipPlanes; j++) + { + bool out = cdc.WorldClipPlanes[j] * *vid[i] > 0; + vid[i]->Flags |= ((uint)out) << j; + } + vid[i]->Flags |= NL3D_SPR_NUM_CLIP_PLANE_SHIFT; + } + triFlag &= vid[i]->Flags; + } + + // If triangle not fully clipped (at least one vertex inside all planes) + if ((triFlag & NL3D_SPR_NUM_CLIP_PLANE_MASK) == 0) + { + visibleTris.push_back(&triId); + } + } + + // Clip and output triangles based on decal clipping mode + if (cdc.ClipMode == DecalClipGeometry) + { + // Geometry clipping: clip each triangle's polygon against the clip planes + static NLMISC::CPolygon clippedTri; + + for (uint triIndex = 0; triIndex < visibleTris.size(); ++triIndex) + { + CTriangleId &triId = *visibleTris[triIndex]; + + // Skip down-facing triangles if requested + if (cdc.ClipDownFacing) + { + CVector triNormal = (_Vertices[triId.Vertex[1]] - _Vertices[triId.Vertex[0]]) ^ (_Vertices[triId.Vertex[2]] - _Vertices[triId.Vertex[0]]); + if (triNormal.z < 0.f) continue; + } + + clippedTri.Vertices.resize(3); + clippedTri.Vertices[0] = _Vertices[triId.Vertex[0]]; + clippedTri.Vertices[1] = _Vertices[triId.Vertex[1]]; + clippedTri.Vertices[2] = _Vertices[triId.Vertex[2]]; + clippedTri.clip(cdc.WorldClipPlanes); + if (clippedTri.Vertices.size() >= 3) + { + for (uint k = 0; k < clippedTri.Vertices.size() - 2; ++k) + { + cdc.DestTris->push_back(clippedTri.Vertices[0] + vertDelta); + cdc.DestTris->push_back(clippedTri.Vertices[k + 1] + vertDelta); + cdc.DestTris->push_back(clippedTri.Vertices[k + 2] + vertDelta); + } + } + } + } + else + { + // No clipping or mask clipping: output full triangles + for (uint triIndex = 0; triIndex < visibleTris.size(); ++triIndex) + { + CTriangleId &triId = *visibleTris[triIndex]; + + // Skip down-facing triangles if requested + if (cdc.ClipDownFacing) + { + CVector triNormal = (_Vertices[triId.Vertex[1]] - _Vertices[triId.Vertex[0]]) ^ (_Vertices[triId.Vertex[2]] - _Vertices[triId.Vertex[0]]); + if (triNormal.z < 0.f) continue; + } + + cdc.DestTris->push_back(_Vertices[triId.Vertex[0]] + vertDelta); + cdc.DestTris->push_back(_Vertices[triId.Vertex[1]] + vertDelta); + cdc.DestTris->push_back(_Vertices[triId.Vertex[2]] + vertDelta); + } + } +} + // *************************************************************************** float CShadowPolyReceiver::getCameraCollision(const CVector &start, const CVector &end, TCameraColTest testType, float radius) { diff --git a/nel/src/3d/u_decal.cpp b/nel/src/3d/u_decal.cpp new file mode 100644 index 0000000000..64fd907ffe --- /dev/null +++ b/nel/src/3d/u_decal.cpp @@ -0,0 +1,152 @@ +/** \file u_decal.cpp + * User interface implementation for projected texture decals. + */ + +/* Copyright, 2007 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "std3d.h" + +#include "nel/3d/u_decal.h" +#include "nel/3d/decal.h" + +namespace NL3D +{ + +// *************************************************************************** +void UDecal::setTexture(const std::string &filename) +{ + CDecal *object = getObjectPtr(); + object->setTexture(filename); +} + +// *************************************************************************** +void UDecal::setMaterialId(uint32 id) +{ + CDecal *object = getObjectPtr(); + object->setMaterialId(id); +} + +// *************************************************************************** +void UDecal::setUVCoord(const NLMISC::CUV &uv1, const NLMISC::CUV &uv2) +{ + CDecal *object = getObjectPtr(); + object->setUVCoord(uv1, uv2); +} + +// *************************************************************************** +void UDecal::setClippingMode(uint mode) +{ + CDecal *object = getObjectPtr(); + TDecalClipMode clipMode; + switch (mode) + { + case 0: clipMode = DecalClipNone; break; + case 1: clipMode = DecalClipMask; break; + case 2: clipMode = DecalClipGeometry; break; + default: clipMode = DecalClipGeometry; break; + } + object->setClippingMode(clipMode); +} + +// *************************************************************************** +void UDecal::setStatic(bool isStatic) +{ + CDecal *object = getObjectPtr(); + object->setStatic(isStatic); +} + +// *************************************************************************** +void UDecal::setDiffuse(NLMISC::CRGBA diffuse) +{ + CDecal *object = getObjectPtr(); + object->setDiffuse(diffuse); +} + +// *************************************************************************** +void UDecal::setEmissive(NLMISC::CRGBA emissive) +{ + CDecal *object = getObjectPtr(); + object->setEmissive(emissive); +} + +// *************************************************************************** +void UDecal::setBottomBlend(float zMin, float zMax) +{ + CDecal *object = getObjectPtr(); + object->setBottomBlend(zMin, zMax); +} + +// *************************************************************************** +void UDecal::setTopBlend(float zMin, float zMax) +{ + CDecal *object = getObjectPtr(); + object->setTopBlend(zMin, zMax); +} + +// *************************************************************************** +void UDecal::setPriority(uint8 priority) +{ + CDecal *object = getObjectPtr(); + object->setPriority(priority); +} + +// *************************************************************************** +void UDecal::setClipDownFacing(bool clipDownFacing) +{ + CDecal *object = getObjectPtr(); + object->setClipDownFacing(clipDownFacing); +} + +// *************************************************************************** +void UDecal::setCustomUVMatrix(bool on, const NLMISC::CMatrix &matrix) +{ + CDecal *object = getObjectPtr(); + object->setCustomUVMatrix(on, matrix); +} + +// *************************************************************************** +void UDecal::setTextureMatrix(const NLMISC::CMatrix &matrix) +{ + CDecal *object = getObjectPtr(); + object->setTextureMatrix(matrix); +} + +// *************************************************************************** +void UDecal::setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth) +{ + CDecal *object = getObjectPtr(); + object->setWorldMatrixForArrow(start, end, halfWidth); +} + +// *************************************************************************** +void UDecal::setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians) +{ + CDecal *object = getObjectPtr(); + object->setWorldMatrixForSpot(pos, radius, angleInRadians); +} + +// *************************************************************************** +bool UDecal::contains(const NLMISC::CVector2f &pos) const +{ + CDecal *object = (CDecal*)_Object; + return object->contains(pos); +} + +} // NL3D diff --git a/nel/src/3d/visual_collision_manager.cpp b/nel/src/3d/visual_collision_manager.cpp index 6d914464fc..74c13aa4e6 100644 --- a/nel/src/3d/visual_collision_manager.cpp +++ b/nel/src/3d/visual_collision_manager.cpp @@ -22,6 +22,7 @@ #include "nel/3d/camera_col.h" #include "nel/3d/shadow_map.h" #include "nel/3d/light.h" +#include "nel/3d/decal.h" #include "nel/misc/common.h" @@ -358,6 +359,33 @@ void CVisualCollisionManager::CMeshInstanceCol::receiveShadowMap(const CVisualC } } + +// *************************************************************************** +void CVisualCollisionManager::receiveDecal(CDecalContext &cdc) +{ + _MeshQuadGrid.select(cdc.WorldBBox.getMin(), cdc.WorldBBox.getMax()); + + CQuadGrid::CIterator it = _MeshQuadGrid.begin(); + CQuadGrid::CIterator itEnd = _MeshQuadGrid.end(); + + for(;it!=itEnd;++it) + { + (*it)->receiveDecal(cdc); + } + +} + +// *************************************************************************** +void CVisualCollisionManager::CMeshInstanceCol::receiveDecal(CDecalContext &cdc) +{ + // if mesh still present (else it s may be an error....) + if(Mesh) + { + // get the collision with the mesh + Mesh->receiveDecal(WorldMatrix, cdc); + } +} + // *************************************************************************** void CVisualCollisionManager::getMeshs(const NLMISC::CAABBox &aabbox, std::vector &dest) { diff --git a/nel/src/3d/visual_collision_mesh.cpp b/nel/src/3d/visual_collision_mesh.cpp index d3bd95b93b..59a59d57c5 100644 --- a/nel/src/3d/visual_collision_mesh.cpp +++ b/nel/src/3d/visual_collision_mesh.cpp @@ -24,6 +24,7 @@ #include "nel/3d/camera_col.h" #include "nel/3d/driver.h" #include "nel/3d/shadow_map.h" +#include "nel/3d/decal.h" using namespace std; @@ -361,6 +362,132 @@ NLMISC::CAABBox CVisualCollisionMesh::computeWorldBBox(const CMatrix &instance return ret; } +// *************************************************************************** +void CVisualCollisionMesh::receiveDecal(const NLMISC::CMatrix &instanceMatrix, CDecalContext &decalContext) +{ + nlassert( decalContext.DestTris ); + // empty mesh => no op + if(_Vertices.empty()) + return; + + // The VertexBuffer RefPtr has been released? quit + if(_VertexBuffer == NULL) + return; + + + // **** Select triangles to be rendered with quadGrid + // select with quadGrid local in mesh + CAABBox localBBox; + localBBox = CAABBox::transformAABBox(decalContext.WorldMatrix.inverted(), decalContext.WorldBBox); + + static std::vector triInQuadGrid; + triInQuadGrid.clear(); + uint numTrisInQuadGrid= _QuadGrid.select(localBBox, triInQuadGrid); + + // no intersection at all? quit + if(numTrisInQuadGrid==0) + return; + + + static std::vector localClipPlanes; + // Allow max bits of planes clip. + localClipPlanes.resize(min((uint)decalContext.WorldClipPlanes.size(), (uint)NL3D_VCM_SHADOW_NUM_CLIP_PLANE)); + // Transform into Mesh local space + for(uint i=0;i vertexFlags; + if(vertexFlags.size()<_Vertices.size()) + vertexFlags.resize(_Vertices.size()); + memset(&vertexFlags[0], 0, _Vertices.size()*sizeof(uint8)); + + + for(uint triq=0; triq 0; + + vf |= ((uint)out)<= 3) + { + for(uint k=0; kpush_back( clippedTri.Vertices[0] ); + decalContext.DestTris->push_back( clippedTri.Vertices[k + 1] ); + decalContext.DestTris->push_back( clippedTri.Vertices[k + 2] ); + } + } + } + else + { + // No clipping or Mask clipping: use faces as-is (mask handles edges via texture stage) + decalContext.DestTris->push_back( instanceMatrix * _Vertices[triId[0]] ); + decalContext.DestTris->push_back( instanceMatrix * _Vertices[triId[1]] ); + decalContext.DestTris->push_back( instanceMatrix * _Vertices[triId[2]] ); + } + } + + } + +} // *************************************************************************** void CVisualCollisionMesh::receiveShadowMap(const NLMISC::CMatrix &instanceMatrix, const CShadowContext &shadowContext) diff --git a/ryzom/client/src/CMakeLists.txt b/ryzom/client/src/CMakeLists.txt index 1ac4d3594a..607c4118f0 100644 --- a/ryzom/client/src/CMakeLists.txt +++ b/ryzom/client/src/CMakeLists.txt @@ -90,8 +90,8 @@ IF(WITH_RYZOM_CLIENT) ) SOURCE_GROUP("outposts" FILES ${RZCLIENT_OUTPOSTS}) FILE(GLOB RZCLIENT_DECALS - decal.cpp decal.h - decal*.cpp decal_*.h + legacy_decal.cpp legacy_decal.h + legacy_decal*.cpp legacy_decal_*.h ) SOURCE_GROUP("decals" FILES ${RZCLIENT_DECALS}) diff --git a/ryzom/client/src/client_cfg.cpp b/ryzom/client/src/client_cfg.cpp index 2b6d31742a..48c8b34f33 100644 --- a/ryzom/client/src/client_cfg.cpp +++ b/ryzom/client/src/client_cfg.cpp @@ -405,6 +405,8 @@ CClientConfig::CClientConfig() SquareBloom = true; DensityBloom = 255.f; + NewDecalSystem = false; + GlobalWindPower = 0.10f; // Default is 0.25 GlobalWindDirection = CVector(1,0,0); // Default direction is X>0 @@ -1031,6 +1033,9 @@ void CClientConfig::setValues() READ_BOOL_FV(SquareBloom) READ_FLOAT_FV(DensityBloom) + // Decal system + READ_BOOL_FV(NewDecalSystem) + // FXAA READ_BOOL_FV(FXAA) diff --git a/ryzom/client/src/client_cfg.h b/ryzom/client/src/client_cfg.h index 80c7c339a0..2b27626108 100644 --- a/ryzom/client/src/client_cfg.h +++ b/ryzom/client/src/client_cfg.h @@ -299,6 +299,9 @@ struct CClientConfig bool SquareBloom; float DensityBloom; + /// Use the new engine-level decal system instead of the legacy client-side one + bool NewDecalSystem; + /// Movie Shooter uint MovieShooterMemory; string MovieShooterPath; diff --git a/ryzom/client/src/landscape_poly_drawer.cpp b/ryzom/client/src/landscape_poly_drawer.cpp index 714684e263..b2e6fab585 100644 --- a/ryzom/client/src/landscape_poly_drawer.cpp +++ b/ryzom/client/src/landscape_poly_drawer.cpp @@ -27,7 +27,8 @@ #include "nel/3d/driver_user.h" // client -#include "decal.h" +#include "legacy_decal.h" +#include "client_cfg.h" using namespace NLMISC; using namespace NL3D; @@ -309,8 +310,12 @@ void CLandscapePolyDrawer::renderLandscapePolyPart() // render decals on landscape only Driver->stencilFunc(UDriver::equal, 0x80, 0x80); - // call to render the decals just before the projected polygons on landscape - CDecalRenderList::getInstance().renderAllDecals(); + // call to render the legacy decals just before the projected polygons on landscape + // (when new decal system is active, rendering is handled by CDecalManager::flush() in render traversal) + if (!ClientCfg.NewDecalSystem) + { + CLegacyDecalRenderList::getInstance().renderAllDecals(); + } // disable stencil test Driver->enableStencilTest(false); diff --git a/ryzom/client/src/decal.cpp b/ryzom/client/src/legacy_decal.cpp similarity index 90% rename from ryzom/client/src/decal.cpp rename to ryzom/client/src/legacy_decal.cpp index ea03cbc30d..6ffe02274a 100644 --- a/ryzom/client/src/decal.cpp +++ b/ryzom/client/src/legacy_decal.cpp @@ -19,7 +19,7 @@ // along with this program. If not, see . #include "stdpch.h" -#include "decal.h" +#include "legacy_decal.h" // #include "nel/3d/shadow_map.h" #include "nel/3d/texture_file.h" @@ -49,12 +49,12 @@ using namespace NLMISC; #define new DEBUG_NEW #endif -CDecalRenderList DecalRenderList; +CLegacyDecalRenderList DecalRenderList; extern uint SkipFrame; -NL3D::CVertexBuffer CDecal::_VB; -bool CDecal::_VBInitialized = false; +NL3D::CVertexBuffer CLegacyDecal::_VB; +bool CLegacyDecal::_VBInitialized = false; @@ -92,7 +92,7 @@ static const char *DecalAttenuationVertexProgramCode = MUL o[COL0].w, v[3].w, R0.w; \n\ END \n"; -class CVertexProgramDecalAttenuation : public CVertexProgram +class CLegacyVertexProgramDecalAttenuation : public CVertexProgram { public: struct CIdx @@ -107,7 +107,7 @@ class CVertexProgramDecalAttenuation : public CVertexProgram // 10 uint BlendScale; // 11 }; - CVertexProgramDecalAttenuation() + CLegacyVertexProgramDecalAttenuation() { // nelvp { @@ -126,7 +126,7 @@ class CVertexProgramDecalAttenuation : public CVertexProgram } // TODO_VP_GLSL } - ~CVertexProgramDecalAttenuation() + ~CLegacyVertexProgramDecalAttenuation() { } @@ -150,17 +150,17 @@ class CVertexProgramDecalAttenuation : public CVertexProgram CIdx m_Idx; }; -static NLMISC::CSmartPtr DecalAttenuationVertexProgram; +static NLMISC::CSmartPtr DecalAttenuationVertexProgram; typedef CShadowPolyReceiver::CRGBAVertex CRGBAVertex; // **************************************************************************** -CDecal::CDecal() +CLegacyDecal::CLegacyDecal() { if (!DecalAttenuationVertexProgram) { - DecalAttenuationVertexProgram = new CVertexProgramDecalAttenuation(); + DecalAttenuationVertexProgram = new CLegacyVertexProgramDecalAttenuation(); } // initialized in render() as depends on scene @@ -207,7 +207,7 @@ CDecal::CDecal() } // **************************************************************************** -void CDecal::setCustomUVMatrix(bool on, const NLMISC::CMatrix &matrix) +void CLegacyDecal::setCustomUVMatrix(bool on, const NLMISC::CMatrix &matrix) { if (_CustomUVMatrix.set(on, matrix)) { @@ -216,7 +216,7 @@ void CDecal::setCustomUVMatrix(bool on, const NLMISC::CMatrix &matrix) } // **************************************************************************** -const std::string &CDecal::getTextureFileName() const +const std::string &CLegacyDecal::getTextureFileName() const { CTextureFile *tf = dynamic_cast(_Material.getTexture(0)); if (tf) return tf->getFileName(); @@ -225,33 +225,33 @@ const std::string &CDecal::getTextureFileName() const } // **************************************************************************** -void CDecal::setupMaterialColor() +void CLegacyDecal::setupMaterialColor() { _Material.texConstantColor(1, NLMISC::CRGBA(_Emissive.R, _Emissive.G, _Emissive.B, _Diffuse.A)); } // **************************************************************************** -void CDecal::setEmissive(NLMISC::CRGBA emissive) +void CLegacyDecal::setEmissive(NLMISC::CRGBA emissive) { _Emissive = emissive; setupMaterialColor(); } // **************************************************************************** -void CDecal::setDiffuse(NLMISC::CRGBA diffuse) +void CLegacyDecal::setDiffuse(NLMISC::CRGBA diffuse) { _Diffuse = diffuse; setupMaterialColor(); } // **************************************************************************** -CRGBA CDecal::getDiffuse() const +CRGBA CLegacyDecal::getDiffuse() const { return _Diffuse; } // **************************************************************************** -CDecal::~CDecal() +CLegacyDecal::~CLegacyDecal() { if (_ShadowMap) { @@ -261,7 +261,7 @@ CDecal::~CDecal() } // **************************************************************************** -void CDecal::setTexture(const std::string &fileName, bool clampU, bool clampV, bool filtered) +void CLegacyDecal::setTexture(const std::string &fileName, bool clampU, bool clampV, bool filtered) { if (getTextureFileName() != fileName) { @@ -302,7 +302,7 @@ void CDecal::setTexture(const std::string &fileName, bool clampU, bool clamp } // **************************************************************************** -void CDecal::setWorldMatrix(const NLMISC::CMatrix &matrix) +void CLegacyDecal::setWorldMatrix(const NLMISC::CMatrix &matrix) { float newMat[16]; matrix.get(newMat); @@ -330,7 +330,7 @@ void CDecal::setWorldMatrix(const NLMISC::CMatrix &matrix) } // **************************************************************************** -bool CDecal::clipFront(const NLMISC::CPlane &p) const +bool CLegacyDecal::clipFront(const NLMISC::CPlane &p) const { for(uint k = 0; k < 8; ++k) { @@ -340,7 +340,7 @@ bool CDecal::clipFront(const NLMISC::CPlane &p) const } // **************************************************************************** -void CDecal::setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth) +void CLegacyDecal::setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLMISC::CVector2f &end, float halfWidth) { CMatrix matrix; CVector I = CVector(end.x, end.y, 0.f) - CVector(start.x, start.y, 0.f); @@ -351,7 +351,7 @@ void CDecal::setWorldMatrixForArrow(const NLMISC::CVector2f &start, const NLM } // **************************************************************************** -void CDecal::setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians) +void CLegacyDecal::setWorldMatrixForSpot(const NLMISC::CVector2f &pos, float radius, float angleInRadians) { CMatrix matrix; matrix.rotateZ(angleInRadians); @@ -365,7 +365,7 @@ NLMISC::CVector r2MaskOffset(1.f / 4.f, 1.f / 4.f, 0.f); // **************************************************************************** -void CDecal::renderTriCache(NL3D::IDriver &drv, NL3D::CShadowPolyReceiver &/* receiver */, bool useVertexProgram) +void CLegacyDecal::renderTriCache(NL3D::IDriver &drv, NL3D::CShadowPolyReceiver &/* receiver */, bool useVertexProgram) { if (_TriCache.empty()) return; if (!_VBInitialized) @@ -379,7 +379,7 @@ void CDecal::renderTriCache(NL3D::IDriver &drv, NL3D::CShadowPolyReceiver &/* drv.setupModelMatrix(modelMat); if (useVertexProgram) { - CVertexProgramDecalAttenuation *program = DecalAttenuationVertexProgram; + CLegacyVertexProgramDecalAttenuation *program = DecalAttenuationVertexProgram; { CVertexBufferReadWrite vba; _VB.setNumVertices((uint32)_TriCache.size()); @@ -441,8 +441,8 @@ void CDecal::renderTriCache(NL3D::IDriver &drv, NL3D::CShadowPolyReceiver &/* const CRGBAVertex *destEnd = dest + _TriCache.size(); const CRGBAVertex *srcVert = &_TriCache[0]; const NLMISC::CVector camPos = MainCam.getMatrix().getPos() - _RefPosition; - float scale = 255.f * CDecalRenderList::getInstance()._DistScale; - float bias = 255.f * CDecalRenderList::getInstance()._DistBias; + float scale = 255.f * CLegacyDecalRenderList::getInstance()._DistScale; + float bias = 255.f * CLegacyDecalRenderList::getInstance()._DistBias; float bottomBlendScale = 1.f / favoid0(_BottomBlendZMax - _BottomBlendZMin); float bottomBlendBias = bottomBlendScale * (_RefPosition.z - _BottomBlendZMin); do @@ -478,7 +478,7 @@ void CDecal::renderTriCache(NL3D::IDriver &drv, NL3D::CShadowPolyReceiver &/* } // **************************************************************************** -void CDecal::render(NL3D::UDriver &/* drv */, +void CLegacyDecal::render(NL3D::UDriver &/* drv */, NL3D::CShadowPolyReceiver &receiver, const std::vector &worldPyramid, const std::vector &pyramidCorners, @@ -617,7 +617,7 @@ void CDecal::render(NL3D::UDriver &/* drv */, } // **************************************************************************** -void CDecalRenderList::renderAllDecals() +void CLegacyDecalRenderList::renderAllDecals() { if (_Empty) return; @@ -655,7 +655,7 @@ void CDecalRenderList::renderAllDecals() } for(uint k = 0; k < DECAL_NUM_PRIORITIES; ++k) { - std::vector &renderList = _RenderList[k]; + std::vector &renderList = _RenderList[k]; for(uint l = 0; l < renderList.size(); ++l) { if (renderList[l]) @@ -671,7 +671,7 @@ void CDecalRenderList::renderAllDecals() } // **************************************************************************** -void CDecalRenderList::clearRenderList() +void CLegacyDecalRenderList::clearRenderList() { for(uint k = 0; k < DECAL_NUM_PRIORITIES; ++k) { @@ -681,27 +681,27 @@ void CDecalRenderList::clearRenderList() } // **************************************************************************** -void CDecal::addToRenderList(uint priority /*=0*/) +void CLegacyDecal::addToRenderList(uint priority /*=0*/) { if( !Landscape) { return; } nlassert(priority < DECAL_NUM_PRIORITIES); - CDecalRenderList &drl = CDecalRenderList::getInstance(); + CLegacyDecalRenderList &drl = CLegacyDecalRenderList::getInstance(); drl._RenderList[priority].push_back(this); drl._Empty = false; } // **************************************************************************** -bool CDecal::contains(const NLMISC::CVector2f &pos) const +bool CLegacyDecal::contains(const NLMISC::CVector2f &pos) const { CVector posIn = _InvertedWorldMatrix * CVector(pos.x, pos.y, 0.f); return posIn.x >= 0.f && posIn.x <= 1.f && posIn.y >= 0.f && posIn.y <= 1.f; } // **************************************************************************** -void CDecal::setClipDownFacing(bool clipDownFacing) +void CLegacyDecal::setClipDownFacing(bool clipDownFacing) { if (clipDownFacing != _ClipDownFacing) { @@ -711,7 +711,7 @@ void CDecal::setClipDownFacing(bool clipDownFacing) } // **************************************************************************** -void CDecal::setBottomBlend(float zMin, float zMax) +void CLegacyDecal::setBottomBlend(float zMin, float zMax) { if (zMin > zMax) std::swap(zMin, zMax); _BottomBlendZMin = zMin; @@ -719,7 +719,7 @@ void CDecal::setBottomBlend(float zMin, float zMax) } // **************************************************************************** -void CDecal::setTopBlend(float zMin, float zMax) +void CLegacyDecal::setTopBlend(float zMin, float zMax) { if (zMin > zMax) std::swap(zMin, zMax); _TopBlendZMin = zMin; diff --git a/ryzom/client/src/decal.h b/ryzom/client/src/legacy_decal.h similarity index 91% rename from ryzom/client/src/decal.h rename to ryzom/client/src/legacy_decal.h index 1c473e74f2..0ca1dee564 100644 --- a/ryzom/client/src/decal.h +++ b/ryzom/client/src/legacy_decal.h @@ -50,13 +50,13 @@ const uint DECAL_NUM_PRIORITIES = 8; // Helper class to display a decal on a poly receiver // Default decal is a unit rectangle (0, 0) - (1, 1) // TODO nico : put this in NL3D when working ? ... -class CDecal : public NLMISC::CRefCount +class CLegacyDecal : public NLMISC::CRefCount { public: - typedef NLMISC::CRefPtr TRefPtr; - typedef NLMISC::CSmartPtr TSmartPtr; - CDecal(); - ~CDecal(); + typedef NLMISC::CRefPtr TRefPtr; + typedef NLMISC::CSmartPtr TSmartPtr; + CLegacyDecal(); + ~CLegacyDecal(); // Set a texture from its filename. It name match a global texture in the view renderer, it will be used ,first void setTexture(const std::string &fileName, bool clampU = true, bool clampV = true, bool filtered = true); NL3D::ITexture *getTexture() { return _Material.getTexture(0); } @@ -108,7 +108,7 @@ class CDecal : public NLMISC::CRefCount float _TopBlendZMin; float _TopBlendZMax; private: - friend class CDecalRenderList; + friend class CLegacyDecalRenderList; void render(NL3D::UDriver &drv, NL3D::CShadowPolyReceiver &receiver, const std::vector &worldPyramid, @@ -121,15 +121,15 @@ class CDecal : public NLMISC::CRefCount }; // list of all decals to be rendered after the landscape -class CDecalRenderList : public NLMISC::CSingleton +class CLegacyDecalRenderList : public NLMISC::CSingleton { public: - CDecalRenderList() : _Empty(true) {} + CLegacyDecalRenderList() : _Empty(true) {} void renderAllDecals(); void clearRenderList(); private: - friend class CDecal; - std::vector _RenderList[DECAL_NUM_PRIORITIES]; + friend class CLegacyDecal; + std::vector _RenderList[DECAL_NUM_PRIORITIES]; bool _Empty; std::vector _WorldCamPyramid; std::vector _WorldCamPyramidCorners; diff --git a/ryzom/client/src/decal_anim.cpp b/ryzom/client/src/legacy_decal_anim.cpp similarity index 89% rename from ryzom/client/src/decal_anim.cpp rename to ryzom/client/src/legacy_decal_anim.cpp index c815961ad9..9773cddeb4 100644 --- a/ryzom/client/src/decal_anim.cpp +++ b/ryzom/client/src/legacy_decal_anim.cpp @@ -19,8 +19,8 @@ #include "stdpch.h" // -#include "decal_anim.h" -#include "decal.h" +#include "legacy_decal_anim.h" +#include "legacy_decal.h" #include "nel/gui/lua_ihm.h" #include "nel/gui/lua_object.h" // @@ -31,7 +31,7 @@ using namespace NLMISC; // ***************************************************************************** -CDecalAnim::CDecalAnim() +CLegacyDecalAnim::CLegacyDecalAnim() { DurationInMs = 1000; EndScaleFactor = 1.f; @@ -43,7 +43,7 @@ CDecalAnim::CDecalAnim() } // ***************************************************************************** -void CDecalAnim::updateDecal(const NLMISC::CVector2f &pos, float animRatio, CDecal &dest, float refScale) const +void CLegacyDecalAnim::updateDecal(const NLMISC::CVector2f &pos, float animRatio, CLegacyDecal &dest, float refScale) const { dest.setTexture(Texture); dest.setWorldMatrixForSpot(pos, refScale * blend(1.f, EndScaleFactor, animRatio), blend(0.f, EndAngleInDegrees, animRatio)); @@ -55,7 +55,7 @@ void CDecalAnim::updateDecal(const NLMISC::CVector2f &pos, float animRatio, CDec // ***************************************************************************** -void CDecalAnim::buildFromLuaTable(CLuaObject &table) +void CLegacyDecalAnim::buildFromLuaTable(CLuaObject &table) { // retrieve a value from a lua table or affect a default value if not found #define GET_LUA_VALUE(dest, Type, CastType, Default) \ diff --git a/ryzom/client/src/decal_anim.h b/ryzom/client/src/legacy_decal_anim.h similarity index 93% rename from ryzom/client/src/decal_anim.h rename to ryzom/client/src/legacy_decal_anim.h index 356e405af0..9e8760ab1a 100644 --- a/ryzom/client/src/decal_anim.h +++ b/ryzom/client/src/legacy_decal_anim.h @@ -33,10 +33,10 @@ namespace NLGUI using namespace NLGUI; -class CDecal; +class CLegacyDecal; // TODO nico : this would fit nicely in the particle system animation system (would be more flexible) -class CDecalAnim +class CLegacyDecalAnim { public: std::string Texture; @@ -49,8 +49,8 @@ class CDecalAnim NLMISC::CRGBA StartEmissive; NLMISC::CRGBA EndEmissive; public: - CDecalAnim(); - void updateDecal(const NLMISC::CVector2f &pos, float animRatio, CDecal &dest, float refScale) const; + CLegacyDecalAnim(); + void updateDecal(const NLMISC::CVector2f &pos, float animRatio, CLegacyDecal &dest, float refScale) const; void buildFromLuaTable(CLuaObject &table); }; diff --git a/ryzom/client/src/main_loop.cpp b/ryzom/client/src/main_loop.cpp index 2ebafa87fe..f6ebd278fa 100644 --- a/ryzom/client/src/main_loop.cpp +++ b/ryzom/client/src/main_loop.cpp @@ -1253,7 +1253,7 @@ bool mainLoop() CInputHandlerManager::getInstance()->pumpEvents(); CLandscapePolyDrawer::getInstance().deletePolygons(); - CDecalRenderList::getInstance().clearRenderList(); + CLegacyDecalRenderList::getInstance().clearRenderList(); // Update the Interface Manager Events. diff --git a/ryzom/client/src/r2/displayer_visual.h b/ryzom/client/src/r2/displayer_visual.h index 844f2a2ff3..90aeb1a7e9 100644 --- a/ryzom/client/src/r2/displayer_visual.h +++ b/ryzom/client/src/r2/displayer_visual.h @@ -25,7 +25,7 @@ #include "nel/misc/vectord.h" #include "nel/misc/rgba.h" // -#include "../decal.h" +#include "../legacy_decal.h" class CGroupInScene; diff --git a/ryzom/client/src/r2/displayer_visual_activity_sequence.cpp b/ryzom/client/src/r2/displayer_visual_activity_sequence.cpp index 1990185c24..d1915e9d9b 100644 --- a/ryzom/client/src/r2/displayer_visual_activity_sequence.cpp +++ b/ryzom/client/src/r2/displayer_visual_activity_sequence.cpp @@ -252,7 +252,7 @@ void CDisplayerVisualActivitySequence::update() void CDisplayerVisualActivitySequence::addFootSteps(const NLMISC::CLine &line) { //H_AUTO(R2_CDisplayerVisualActivitySequence_addFootSteps) - CDecal *decal = new CDecal; + CLegacyDecal *decal = new CLegacyDecal; decal->setTexture(CV_FootStepDecalTexture.get(), false, true); CVector2f start2f(line.V0.x, line.V0.y); CVector2f end2f(line.V1.x, line.V1.y); @@ -272,7 +272,7 @@ void CDisplayerVisualActivitySequence::addFootSteps(const NLMISC::CLine &line) void CDisplayerVisualActivitySequence::addWanderSteps(const CVector &pos) { //H_AUTO(R2_CDisplayerVisualActivitySequence_addWanderSteps) - CDecal *decal = new CDecal; + CLegacyDecal *decal = new CLegacyDecal; decal->setTexture(CV_WanderDecalTexture.get(), true, true); decal->setWorldMatrixForSpot(CVector2f(pos.x, pos.y), CV_WanderDecalSize.get()); _Decals.push_back(decal); diff --git a/ryzom/client/src/r2/displayer_visual_activity_sequence.h b/ryzom/client/src/r2/displayer_visual_activity_sequence.h index 290c623098..45c63e8502 100644 --- a/ryzom/client/src/r2/displayer_visual_activity_sequence.h +++ b/ryzom/client/src/r2/displayer_visual_activity_sequence.h @@ -18,7 +18,7 @@ #define R2_DISPLAYER_VISUAL_ACTIVITY_SEQUENCE_H #include "displayer_visual.h" -#include "../decal.h" +#include "../legacy_decal.h" #include "editor.h" #include "nel/misc/line.h" // @@ -52,7 +52,7 @@ class CDisplayerVisualActivitySequence : public CDisplayerVisual, public CEditor bool _AddedToWorldMap; bool _Touched; bool _Active; - std::vector _Decals; + std::vector _Decals; std::vector _WorldMapEdges; std::vector _ObserverHandles; // need to know when one of the component world pos is changed (no notification message reach us if diff --git a/ryzom/client/src/r2/displayer_visual_entity.h b/ryzom/client/src/r2/displayer_visual_entity.h index f5bf4ea94c..6ca49b7e7b 100644 --- a/ryzom/client/src/r2/displayer_visual_entity.h +++ b/ryzom/client/src/r2/displayer_visual_entity.h @@ -22,7 +22,7 @@ #include "displayer_visual.h" #include "instance.h" -#include "../decal.h" +#include "../legacy_decal.h" #include "nel/gui/lua_object.h" #include "instance_map_deco.h" diff --git a/ryzom/client/src/r2/editor.cpp b/ryzom/client/src/r2/editor.cpp index 4f6968bff1..09c12a70e7 100644 --- a/ryzom/client/src/r2/editor.cpp +++ b/ryzom/client/src/r2/editor.cpp @@ -2988,7 +2988,7 @@ void CEditor::initDecals() // ********************************************************************************************************* -void CEditor::showPrimRender(CPrimRender &dest, const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat, const CDecalAnim &refDecalAnim) +void CEditor::showPrimRender(CPrimRender &dest, const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat, const CLegacyDecalAnim &refDecalAnim) { //H_AUTO(R2_CEditor_showPrimRender) CHECK_EDITOR @@ -3055,7 +3055,7 @@ void CEditor::showHighlightDecal(const NLMISC::CVector &pos, float scale) } // ********************************************************************************************************* -void CEditor::showDecal(const NLMISC::CVector2f &pos, float scale, CDecal &decal, const CDecalAnim &decalAnim) +void CEditor::showDecal(const NLMISC::CVector2f &pos, float scale, CLegacyDecal &decal, const CLegacyDecalAnim &decalAnim) { //H_AUTO(R2_CEditor_showDecal) CHECK_EDITOR @@ -4712,7 +4712,7 @@ void CEditor::updateBeforeRender() } // ********************************************************************************************************* -void CEditor::updateDecalBlendRegion(CDecal &decal, const NLMISC::CVector &pos) +void CEditor::updateDecalBlendRegion(CLegacyDecal &decal, const NLMISC::CVector &pos) { //H_AUTO(R2_CEditor_updateDecalBlendRegion) float topBlendDist = CV_DecalTopBlendStartDist.get(); diff --git a/ryzom/client/src/r2/editor.h b/ryzom/client/src/r2/editor.h index 3b3f970b09..214e74a53c 100644 --- a/ryzom/client/src/r2/editor.h +++ b/ryzom/client/src/r2/editor.h @@ -23,8 +23,8 @@ #include "nel/gui/lua_object.h" #include "instance.h" #include "tool.h" -#include "../decal.h" -#include "../decal_anim.h" +#include "../legacy_decal.h" +#include "../legacy_decal_anim.h" #include "entity_custom_select_box.h" #include "island_collision.h" #include "prim_render.h" @@ -669,22 +669,22 @@ class CEditor : public NLMISC::CSingleton CTool::TSmartPtr _CurrentTool; static bool _ReloadWanted; // - CDecal _HighlightDecal; - CDecalAnim _HighlightDecalAnim; - CDecal _SelectDecal; - CDecalAnim _SelectDecalAnim; - CDecalAnim _SelectingDecalAnim; - CDecal _PionneerDecal; + CLegacyDecal _HighlightDecal; + CLegacyDecalAnim _HighlightDecalAnim; + CLegacyDecal _SelectDecal; + CLegacyDecalAnim _SelectDecalAnim; + CLegacyDecalAnim _SelectingDecalAnim; + CLegacyDecal _PionneerDecal; // alternative selection for huge element like particle systems, display a box on ground rather than // the selection circle CPrimRender _SelectBox; CPrimRender _HighlightBox; // NLMISC::TTime _LastAutoSaveTime; - CDecalAnim _PionneerDecalAnim; + CLegacyDecalAnim _PionneerDecalAnim; struct CSelectingDecal : public NLMISC::CRefCount { - CDecal Decal; + CLegacyDecal Decal; sint64 EndDate; NLMISC::CVector Pos; float Scale; @@ -924,7 +924,7 @@ class CEditor : public NLMISC::CSingleton void saveCurrentKeySet(); void reloadUI(const char *filename); void initHighlightDecal(); - void updateDecalBlendRegion(CDecal &decal, const NLMISC::CVector &pos); + void updateDecalBlendRegion(CLegacyDecal &decal, const NLMISC::CVector &pos); void initPalette(); void initObjectProjectionMetatable(); void registerDisplayers(); @@ -935,7 +935,7 @@ class CEditor : public NLMISC::CSingleton void registerEnvFunction(const char *name, TLuaWrappedFunction func); // Initialisation of contextual cursor. void initDecals(); - void showDecal(const NLMISC::CVector2f &pos, float scale, CDecal &decal, const CDecalAnim &decalAnim); + void showDecal(const NLMISC::CVector2f &pos, float scale, CLegacyDecal &decal, const CLegacyDecalAnim &decalAnim); void updatePrimitiveContextualVisibility(); void initClassInheritanceTable(); // contextual mouse handling @@ -947,9 +947,9 @@ class CEditor : public NLMISC::CSingleton // update the display of decals created when the player select an instance in the scene void updateSelectingDecals(); // display of highlight or select box (for selection of huge objects) - // the CDecalAnim is used to mimic the color cycle seen when standard selection circle is displayed + // the CLegacyDecalAnim is used to mimic the color cycle seen when standard selection circle is displayed // (no CPrimRenderAnim for now) - void showPrimRender(CPrimRender &dest, const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat, const CDecalAnim &refDecalAnim); + void showPrimRender(CPrimRender &dest, const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat, const CLegacyDecalAnim &refDecalAnim); CLuaObject _OldLuaRequestInsertNode; CLuaObject _OldLuaRequestInsertGhostNode; diff --git a/ryzom/client/src/r2/prim_render.cpp b/ryzom/client/src/r2/prim_render.cpp index 93f610377f..048f237048 100644 --- a/ryzom/client/src/r2/prim_render.cpp +++ b/ryzom/client/src/r2/prim_render.cpp @@ -366,7 +366,7 @@ void CPrimRender::update() _VertexDecals.resize(_Vertices.size()); for(uint k = 0; k < _Vertices.size(); ++k) { - _VertexDecals[k] = new CDecal; + _VertexDecals[k] = new CLegacyDecal; _VertexDecals[k]->setClipDownFacing(_Look.ClipDownFacing); if (k == 0 && !_Look.FirstVertexLook.DecalTexture.empty()) { @@ -418,7 +418,7 @@ void CPrimRender::update() _EdgeDecals.resize(_NumEdges); for(sint k = 0; k < _NumEdges; ++k) { - _EdgeDecals[k] = new CDecal; + _EdgeDecals[k] = new CLegacyDecal; _EdgeDecals[k]->setClipDownFacing(_Look.ClipDownFacing); _EdgeDecals[k]->setTexture(_Look.EdgeLook.DecalTexture, _Look.EdgeLook.DecalWrapMode == CEdgeLook::Centered, true, _Look.EdgeLook.DecalFiltered); _EdgeDecals[k]->setDiffuse(_Look.EdgeLook.DecalColor); @@ -541,7 +541,7 @@ void CPrimRender::updateEdge(NL3D::UInstance edge,const NLMISC::CVector &start, } // ********************************************************* -void CPrimRender::updateEdgeDecal(CDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex) +void CPrimRender::updateEdgeDecal(CLegacyDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex) { //H_AUTO(R2_CPrimRender_updateEdgeDecal) CVector2f start2f(start.x, start.y); diff --git a/ryzom/client/src/r2/prim_render.h b/ryzom/client/src/r2/prim_render.h index 7d2f708ed9..3062adfe7c 100644 --- a/ryzom/client/src/r2/prim_render.h +++ b/ryzom/client/src/r2/prim_render.h @@ -225,8 +225,8 @@ class CPrimRender : public CGroupMap::IDeco // CMeshArray _VertexShapeInstances; CMeshArray _EdgeShapeInstances; - std::vector _VertexDecals; - std::vector _EdgeDecals; // Decal of edges on landscape + std::vector _VertexDecals; + std::vector _EdgeDecals; // Decal of edges on landscape NLMISC::CRGBA _Emissive; sint _NumEdges; float _InvWorldTextureWidth; @@ -238,7 +238,7 @@ class CPrimRender : public CGroupMap::IDeco void update(); void updatePos(); void updateEdge(NL3D::UInstance edge, const NLMISC::CVector &start, const NLMISC::CVector &end); - void updateEdgeDecal(CDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex); + void updateEdgeDecal(CLegacyDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex); void forceSetEmissive(NLMISC::CRGBA emissive); // world map display void setWorldMapNumVertices(uint count); diff --git a/ryzom/client/src/r2/tool_choose_pos.h b/ryzom/client/src/r2/tool_choose_pos.h index 913dad3c11..0ae2a8a677 100644 --- a/ryzom/client/src/r2/tool_choose_pos.h +++ b/ryzom/client/src/r2/tool_choose_pos.h @@ -21,7 +21,7 @@ #define R2_TOOL_CHOOSE_POS_H #include "tool.h" -#include "../decal.h" +#include "../legacy_decal.h" #include "prim_render.h" #include "nel/misc/vector.h" #include "nel/misc/polygon.h" @@ -92,8 +92,8 @@ class CToolChoosePos : public CTool bool _Valid; NLMISC::CVector _CreatePosition; private: - CDecal _BadPlaceDecal; - CDecal _TestDecal; + CLegacyDecal _BadPlaceDecal; + CLegacyDecal _TestDecal; bool _MultiPos; bool _MultiPosLocked; float _CreateAngle; diff --git a/ryzom/client/src/r2/tool_create_entity.h b/ryzom/client/src/r2/tool_create_entity.h index a6c174b223..eca2e2f56e 100644 --- a/ryzom/client/src/r2/tool_create_entity.h +++ b/ryzom/client/src/r2/tool_create_entity.h @@ -23,7 +23,7 @@ #include "tool_choose_pos.h" #include "nel/misc/vector.h" #include "prim_render.h" -#include "../decal.h" +#include "../legacy_decal.h" #include "auto_group.h" #include "displayer_visual_entity.h" diff --git a/ryzom/client/src/r2/tool_draw_prim.h b/ryzom/client/src/r2/tool_draw_prim.h index c1b0b43f4f..9d14e471f3 100644 --- a/ryzom/client/src/r2/tool_draw_prim.h +++ b/ryzom/client/src/r2/tool_draw_prim.h @@ -22,7 +22,7 @@ #include "tool.h" #include "prim_render.h" -#include "../decal.h" +#include "../legacy_decal.h" // #include "nel/misc/vector.h" @@ -90,7 +90,7 @@ class CToolDrawPrim : public CTool bool _Extending; bool _Commited; bool _ForceShowPrims; - CDecal _TestDecal; + CLegacyDecal _TestDecal; private: void commit(); void setPrimLook(bool closed, bool lastSegmentValid, bool valid);