/**
* @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 .
*/
#pragma once
#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];
};