/** * @file MeshEntity.h * Declares the MeshEntity class. * @ingroup meshtex-core */ /* * Copyright 2012 Joel Baxter * * This file is part of MeshTex. * * MeshTex 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 of the License, or * (at your option) any later version. * * MeshTex 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 MeshTex. If not, see . */ #if !defined(INCLUDED_MESHENTITY_H) #define INCLUDED_MESHENTITY_H #include "AllocatedMatrix.h" #include "scenelib.h" #include "ipatch.h" #include "generic/callback.h" /** * Wrapper for a biquadratic Bezier patch mesh entity from Radiant. * Instantiate this for a given patch mesh, then use the methods to * interrogate or modify the mesh. It is intended that this object be * instantiated, used, and then discarded before resuming other Radiant * operations, as the implementation assumes that several basic mesh * characteristics will remain constant for the life of this object. * * @ingroup meshtex-core */ class MeshEntity { public: // public types /** * Values that represent the texture axes an operation should manipulate. */ enum TextureAxisSelection { S_TEX_AXIS_ONLY, ///< manipulate the S values T_TEX_AXIS_ONLY, ///< manipulate the T values ALL_TEX_AXES ///< manipulate both S and T values }; /** * Values that represent the kinds of patch mesh slices. Note that the * assigned integer values are significant; do not change. */ enum SliceType { ROW_SLICE_TYPE = 0, ///< row COL_SLICE_TYPE = 1, ///< column NUM_SLICE_TYPES = 2 ///< number of kinds of slice }; /** * Type for info/warning/error callbacks. The callback takes a const * char* argument (the message string); it has no return value. */ typedef Callback1 MessageCallback; /** * Type for texture scale info callbacks. The callback takes two float * arguments (scale and tiles); it has no return value. */ typedef Callback2 TexInfoCallback; /** * Type for defining how to manipulate control point or surface values * according to some linear combination of various values. */ typedef struct { float oldValue; ///< coefficient for original value float rowDistance; ///< coefficient for surface distance along row float colDistance; ///< coefficient for surface distance along col float rowNumber; ///< coefficient for row number float colNumber; ///< coefficient for column number float constant; ///< constant } GeneralFunctionFactors; /** * Type for choosing a particular slice of a known kind (row or column). */ typedef struct { bool maxSlice; ///< if true, choose slice with highest index int index; ///< if maxSlice is false, choose slice with this index } SliceDesignation; /** * Type for choosing a reference slice of a known kind (row or column) and * indicating how to use it for reference. Reference can be made to the total * slice surface length alone, or to each individual control point. */ typedef struct { SliceDesignation designation; ///< the slice bool totalLengthOnly; ///< if true, reference total length only } RefSliceDescriptor; /** * An instance of this class can be used as a MeshEntity::TexInfoCallback, in * situations where the callback is a method to be invoked on a target * object. When invoking this constructor, the target object is the * constructor argument, and the target object class and method are template * parameters. The target object's method must have an appropriate signature * for TexInfoCallback: two float arguments, void return. */ template class TexInfoCallbackMethod : public BindFirstOpaque2 > { public: /** * Constructor. * * @param object The object on which to invoke the callback method. */ TexInfoCallbackMethod(ObjectClass& object) : BindFirstOpaque2 >(object) {} }; public: // public methods /// @name Lifecycle //@{ MeshEntity(scene::Node& mesh, const MessageCallback& infoReportCallback, const MessageCallback& warningReportCallback, const MessageCallback& errorReportCallback); ~MeshEntity(); //@} /// @name Interrogation //@{ bool IsValid() const; void GetInfo(const int *refRow, const int *refCol, const TexInfoCallback *rowTexInfoCallback, const TexInfoCallback *colTexInfoCallback); //@} /// @name Simple modification //@{ void MinAlign(TextureAxisSelection axes); void MaxAlign(TextureAxisSelection axes); void MinMaxAlignAutoScale(TextureAxisSelection axes); void MinMaxAlignStretch(TextureAxisSelection axes); void MinMaxAlignShrink(TextureAxisSelection axes); //@} /// @name Complex modification //@{ void SetScale(SliceType sliceType, const SliceDesignation *alignSlice, const RefSliceDescriptor *refSlice, bool naturalScale, float naturalScaleOrTiles); void GeneralFunction(const GeneralFunctionFactors *sFactors, const GeneralFunctionFactors *tFactors, const SliceDesignation *alignRow, const SliceDesignation *alignCol, const RefSliceDescriptor *refRow, const RefSliceDescriptor *refCol, bool surfaceValues); //@} private: // private methods /// @name Unimplemented to prevent copy/assignment //@{ MeshEntity(const MeshEntity&); const MeshEntity& operator=(const MeshEntity&); //@} private: // private types /** * Values that represent the kinds of texture axis. */ enum TextureAxis { S_TEX_AXIS = 0, ///< S texture axis T_TEX_AXIS = 1, ///< T texture axis NUM_TEX_AXES = 2 ///< number of kinds of texture axis }; /** * Values that represent the kinds of position (spatial) axis. */ enum PositionAxis { X_POS_AXIS = 0, ///< X position axis Y_POS_AXIS = 1, ///< Y position axis Z_POS_AXIS = 2, ///< Z position axis NUM_POS_AXES = 3 ///< number of kinds of position axis }; /** * Values that represent ways of scaling a texture to make it aligned. */ enum ScaleOperation { STRETCH_SCALE_OP, ///< scale by stretching SHRINK_SCALE_OP ///< scale by shrinking }; /** * Type for orienting a slice within a particular patch. */ typedef struct { SliceType sliceType; ///< slice type (row or column) float position; ///< fractional dist from patch edge (0, 0.5, or 1) int edgeSlice[NUM_SLICE_TYPES]; ///< indices of slices at patch edges } SlicePatchContext; /** * Type for describing the application of a texture along a given slice, * on a specified texture axis. */ typedef struct { float scale; ///< texture scale along axis float tiles; ///< # of times the texture tiles along axis float min; ///< minimum value for that texture axis float max; ///< maximum value for that texture axis } SliceTexInfo; /** * Type for internal representation of a reference slice of a given kind * (row or column), specifying the slice and indicating how to use it for * reference. Any external specification of "max slice" has been replaced * with an explicit slice number. Reference can be made to the total slice * length alone, or to the distance to each individual control point. */ typedef struct { unsigned index; ///< choose slice with this number bool totalLengthOnly; ///< if true, reference total length only } RefSliceDescriptorInt; /** * Function signature for a private method that applies a preset * transformation on a given texture axis. */ typedef bool(MeshEntity::*InternalImpl)(TextureAxis axis); private: // private template methods /** * Utility template function for accessing a matrix element from code that * operates on either kind of slice. * * @param matrix The matrix holding the mesh control points. * @param sliceType Slice kind (row or column). * @param slice Slice number, among slices of that type in mesh. * @param index Element index along the slice. * * @return The matrix element; can be used as lvalue or rvalue. */ template inline static Element& MatrixElement(Matrix& matrix, SliceType sliceType, int slice, int index) { return (sliceType == ROW_SLICE_TYPE ? matrix(slice, index) : matrix(index, slice)); } private: // private methods /// @name Internal state refresh //@{ void UpdatePosMinMax(PositionAxis axis); void UpdateTexMinMax(TextureAxis axis); //@} /// @name Radiant state management //@{ void CreateUndoPoint(); void CommitChanges(); //@} /// @name Argument resolution //@{ int InternalSliceDesignation(const SliceDesignation *sliceDesignation, SliceType sliceType); RefSliceDescriptorInt *InternalRefSliceDescriptor(const RefSliceDescriptor *refSlice, SliceType sliceType, RefSliceDescriptorInt& refSliceInt); //@} /// @name Subroutines for interrogation //@{ float GetSliceTexScale(SliceType sliceType, int slice, TextureAxis axis, float tiles); bool GetSliceTexInfo(SliceType sliceType, int slice, TextureAxis axis, SliceTexInfo& info); void ReportSliceTexInfo(SliceType sliceType, int slice, TextureAxis axis, char *messageBuffer, unsigned messageBufferSize, const TexInfoCallback *texInfoCallback); //@} /// @name Subroutines for simple modification //@{ void ProcessForAxes(InternalImpl internalImpl, TextureAxisSelection axes); void Shift(TextureAxis axis, float shift); void Scale(TextureAxis axis, float scale); bool MinAlignInt(TextureAxis axis); bool MaxAlignInt(TextureAxis axis); bool MinMaxAlignAutoScaleInt(TextureAxis axis); bool MinMaxAlignScale(TextureAxis axis, ScaleOperation op); bool MinMaxAlignStretchInt(TextureAxis axis); bool MinMaxAlignShrinkInt(TextureAxis axis); //@} /// @name Surface measurement //@{ float SliceParametricSpeedComponent(PositionAxis axis, float t, const SlicePatchContext& context); float SliceParametricSpeed(float t, const SlicePatchContext& context); float EstimateSegmentLength(float startPosition, float endPosition, const SlicePatchContext& context); float RefineSegmentLength(float startPosition, float endPosition, const SlicePatchContext &context, float segmentLengthEstimate, float maxError); //@} /// @name Subroutines for complex modification //@{ void GenControlTexFromSurface(TextureAxis axis, const Matrix& surfaceValues); void CopyControlTexFromValues(TextureAxis axis, const Matrix& values); void GenSurfaceFromControlTex(TextureAxis axis, Matrix& surfaceValues); void CopyValuesFromControlTex(TextureAxis axis, Matrix& values); void GenScaledDistanceValues(SliceType sliceType, int alignSlice, const RefSliceDescriptorInt *refSlice, bool rawScale, float rawScaleOrTiles, Matrix& values); void GeneralFunctionInt(const GeneralFunctionFactors& factors, TextureAxis axis, int alignRow, int alignCol, bool surfaceValues, const Matrix& rowDistances, const Matrix& colDistances); //@} private: // private static member vars static TextureAxis _naturalAxis[NUM_SLICE_TYPES]; static bool _radiantScaleInverted[NUM_SLICE_TYPES]; static bool _radiantTilesInverted[NUM_SLICE_TYPES]; static const char *_infoSliceFormatString[NUM_SLICE_TYPES]; static const char *_infoSliceInfscaleFormatString[NUM_SLICE_TYPES]; static const char *_warningSliceInfscaleFormatString[NUM_SLICE_TYPES]; static const char *_errorBadSliceString[NUM_SLICE_TYPES]; static const char *_errorSliceZeroscaleString[NUM_SLICE_TYPES]; static const char *_errorSliceZerotilesString[NUM_SLICE_TYPES]; private: // private member vars /** * Handle for the Node object in Radiant that is the patch mesh entity. */ scene::Node& _mesh; /** * Flag to indicate whether this object was properly generated from the * supplied entity. */ bool _valid; /** * The control points of the mesh. Modifying the data in this matrix will * modify the mesh entity directly; it is NOT a copy of the entity's data. */ PatchControlMatrix _meshData; /** * Callback function used to report information about the mesh. */ const MessageCallback _infoReportCallback; /** * Callback function used to deliver warning messages. */ const MessageCallback _warningReportCallback; /** * Callback function used to deliver error messages when operations on the * mesh fail. */ const MessageCallback _errorReportCallback; /** * The number of grid units that would constitute a "natural" scale along * each texture axis, using the mesh's current texture. Radiant's natural * scale is 1/2 as many grid units as there are texture pixels. */ float _naturalTexUnits[NUM_TEX_AXES]; /** * The number of mesh slices of each kind (row or column). */ unsigned _numSlices[NUM_SLICE_TYPES]; /** * Whether the values for a texture axis have been modified since the last * time their min/max/aligned state was calculated. */ bool _texMinMaxDirty[NUM_TEX_AXES]; /** * The minimum values, across the entire mesh, for each texture axis. */ float _texMin[NUM_TEX_AXES]; /** * The maximum values, across the entire mesh, for each texture axis. */ float _texMax[NUM_TEX_AXES]; /** * Whether the minimum value for a texture axis is on a texture boundary. */ bool _texMinAligned[NUM_TEX_AXES]; /** * Whether the maximum value for a texture axis is on a texture boundary. */ bool _texMaxAligned[NUM_TEX_AXES]; /** * The minimum values, across the entire mesh, for each position axis. */ float _posMin[NUM_POS_AXES]; /** * The maximum values, across the entire mesh, for each position axis. */ float _posMax[NUM_POS_AXES]; }; #endif // #if !defined(INCLUDED_MESHENTITY_H)