X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fpatch.cpp;h=c48cb44a4fa522929e9a53921d2deaa324c227ea;hb=42856811f2b174e37a761bfcb9fbeb8c6af2f558;hp=b31def460421835a87b98173fc706e21e7e24991;hpb=7fc621fc78d0e040dc2c12f38dc53dd9048215dc;p=xonotic%2Fnetradiant.git diff --git a/radiant/patch.cpp b/radiant/patch.cpp index b31def46..c48cb44a 100644 --- a/radiant/patch.cpp +++ b/radiant/patch.cpp @@ -29,18 +29,20 @@ Signal0 g_patchTextureChangedCallbacks; -void Patch_addTextureChangedCallback( const SignalHandler& handler ){ - g_patchTextureChangedCallbacks.connectLast( handler ); +void Patch_addTextureChangedCallback(const SignalHandler &handler) +{ + g_patchTextureChangedCallbacks.connectLast(handler); } -void Patch_textureChanged(){ - g_patchTextureChangedCallbacks(); +void Patch_textureChanged() +{ + g_patchTextureChangedCallbacks(); } -Shader* PatchInstance::m_state_selpoint; -Shader* Patch::m_state_ctrl; -Shader* Patch::m_state_lattice; +Shader *PatchInstance::m_state_selpoint; +Shader *Patch::m_state_ctrl; +Shader *Patch::m_state_lattice; EPatchType Patch::m_type; @@ -49,237 +51,238 @@ std::size_t MAX_PATCH_HEIGHT = 0; int g_PatchSubdivideThreshold = 4; -void BezierCurveTree_Delete( BezierCurveTree *pCurve ){ - if ( pCurve ) { - BezierCurveTree_Delete( pCurve->left ); - BezierCurveTree_Delete( pCurve->right ); - delete pCurve; - } +void BezierCurveTree_Delete(BezierCurveTree *pCurve) +{ + if (pCurve) { + BezierCurveTree_Delete(pCurve->left); + BezierCurveTree_Delete(pCurve->right); + delete pCurve; + } } -std::size_t BezierCurveTree_Setup( BezierCurveTree *pCurve, std::size_t index, std::size_t stride ){ - if ( pCurve ) { - if ( pCurve->left && pCurve->right ) { - index = BezierCurveTree_Setup( pCurve->left, index, stride ); - pCurve->index = index * stride; - index++; - index = BezierCurveTree_Setup( pCurve->right, index, stride ); - } - else - { - pCurve->index = BEZIERCURVETREE_MAX_INDEX; - } - } +std::size_t BezierCurveTree_Setup(BezierCurveTree *pCurve, std::size_t index, std::size_t stride) +{ + if (pCurve) { + if (pCurve->left && pCurve->right) { + index = BezierCurveTree_Setup(pCurve->left, index, stride); + pCurve->index = index * stride; + index++; + index = BezierCurveTree_Setup(pCurve->right, index, stride); + } else { + pCurve->index = BEZIERCURVETREE_MAX_INDEX; + } + } - return index; + return index; } -bool BezierCurve_IsCurved( BezierCurve *pCurve ){ - Vector3 vTemp( vector3_subtracted( pCurve->right, pCurve->left ) ); - Vector3 v1( vector3_subtracted( pCurve->crd, pCurve->left ) ); - Vector3 v2( vector3_subtracted( pCurve->right, pCurve->crd ) ); +bool BezierCurve_IsCurved(BezierCurve *pCurve) +{ + Vector3 vTemp(vector3_subtracted(pCurve->right, pCurve->left)); + Vector3 v1(vector3_subtracted(pCurve->crd, pCurve->left)); + Vector3 v2(vector3_subtracted(pCurve->right, pCurve->crd)); - if ( vector3_equal( v1, g_vector3_identity ) || vector3_equal( vTemp, v1 ) ) { // return 0 if 1->2 == 0 or 1->2 == 1->3 - return false; - } + if (vector3_equal(v1, g_vector3_identity) || vector3_equal(vTemp, v1)) { // return 0 if 1->2 == 0 or 1->2 == 1->3 + return false; + } - vector3_normalise( v1 ); - vector3_normalise( v2 ); - if ( vector3_equal( v1, v2 ) ) { - return false; - } + vector3_normalise(v1); + vector3_normalise(v2); + if (vector3_equal(v1, v2)) { + return false; + } - Vector3 v3( vTemp ); - const double width = vector3_length( v3 ); - vector3_scale( v3, 1.0 / width ); + Vector3 v3(vTemp); + const double width = vector3_length(v3); + vector3_scale(v3, 1.0 / width); - if ( vector3_equal( v1, v3 ) && vector3_equal( v2, v3 ) ) { - return false; - } + if (vector3_equal(v1, v3) && vector3_equal(v2, v3)) { + return false; + } - const double angle = acos( vector3_dot( v1, v2 ) ) / c_pi; + const double angle = acos(vector3_dot(v1, v2)) / c_pi; - const double index = width * angle; + const double index = width * angle; - if ( index > static_cast( g_PatchSubdivideThreshold ) ) { - return true; - } - return false; + if (index > static_cast( g_PatchSubdivideThreshold )) { + return true; + } + return false; } -void BezierInterpolate( BezierCurve *pCurve ){ - pCurve->left = vector3_mid( pCurve->left, pCurve->crd ); - pCurve->right = vector3_mid( pCurve->crd, pCurve->right ); - pCurve->crd = vector3_mid( pCurve->left, pCurve->right ); +void BezierInterpolate(BezierCurve *pCurve) +{ + pCurve->left = vector3_mid(pCurve->left, pCurve->crd); + pCurve->right = vector3_mid(pCurve->crd, pCurve->right); + pCurve->crd = vector3_mid(pCurve->left, pCurve->right); } const std::size_t PATCH_MAX_SUBDIVISION_DEPTH = 16; -void BezierCurveTree_FromCurveList( BezierCurveTree *pTree, GSList *pCurveList, std::size_t depth = 0 ){ - GSList *pLeftList = 0; - GSList *pRightList = 0; - BezierCurve *pCurve, *pLeftCurve, *pRightCurve; - bool bSplit = false; - - for ( GSList *l = pCurveList; l; l = l->next ) - { - pCurve = (BezierCurve *)( l->data ); - if ( bSplit || BezierCurve_IsCurved( pCurve ) ) { - bSplit = true; - pLeftCurve = new BezierCurve; - pRightCurve = new BezierCurve; - pLeftCurve->left = pCurve->left; - pRightCurve->right = pCurve->right; - BezierInterpolate( pCurve ); - pLeftCurve->crd = pCurve->left; - pRightCurve->crd = pCurve->right; - pLeftCurve->right = pCurve->crd; - pRightCurve->left = pCurve->crd; - - pLeftList = g_slist_prepend( pLeftList, pLeftCurve ); - pRightList = g_slist_prepend( pRightList, pRightCurve ); - } - } - - if ( pLeftList != 0 && pRightList != 0 && depth != PATCH_MAX_SUBDIVISION_DEPTH ) { - pTree->left = new BezierCurveTree; - pTree->right = new BezierCurveTree; - BezierCurveTree_FromCurveList( pTree->left, pLeftList, depth + 1 ); - BezierCurveTree_FromCurveList( pTree->right, pRightList, depth + 1 ); - - for ( GSList* l = pLeftList; l != 0; l = g_slist_next( l ) ) - { - delete (BezierCurve*)l->data; - } - - for ( GSList* l = pRightList; l != 0; l = g_slist_next( l ) ) - { - delete (BezierCurve*)l->data; - } - - g_slist_free( pLeftList ); - g_slist_free( pRightList ); - } - else - { - pTree->left = 0; - pTree->right = 0; - } +void BezierCurveTree_FromCurveList(BezierCurveTree *pTree, GSList *pCurveList, std::size_t depth = 0) +{ + GSList *pLeftList = 0; + GSList *pRightList = 0; + BezierCurve *pCurve, *pLeftCurve, *pRightCurve; + bool bSplit = false; + + for (GSList *l = pCurveList; l; l = l->next) { + pCurve = (BezierCurve *) (l->data); + if (bSplit || BezierCurve_IsCurved(pCurve)) { + bSplit = true; + pLeftCurve = new BezierCurve; + pRightCurve = new BezierCurve; + pLeftCurve->left = pCurve->left; + pRightCurve->right = pCurve->right; + BezierInterpolate(pCurve); + pLeftCurve->crd = pCurve->left; + pRightCurve->crd = pCurve->right; + pLeftCurve->right = pCurve->crd; + pRightCurve->left = pCurve->crd; + + pLeftList = g_slist_prepend(pLeftList, pLeftCurve); + pRightList = g_slist_prepend(pRightList, pRightCurve); + } + } + + if (pLeftList != 0 && pRightList != 0 && depth != PATCH_MAX_SUBDIVISION_DEPTH) { + pTree->left = new BezierCurveTree; + pTree->right = new BezierCurveTree; + BezierCurveTree_FromCurveList(pTree->left, pLeftList, depth + 1); + BezierCurveTree_FromCurveList(pTree->right, pRightList, depth + 1); + + for (GSList *l = pLeftList; l != 0; l = g_slist_next(l)) { + delete (BezierCurve *) l->data; + } + + for (GSList *l = pRightList; l != 0; l = g_slist_next(l)) { + delete (BezierCurve *) l->data; + } + + g_slist_free(pLeftList); + g_slist_free(pRightList); + } else { + pTree->left = 0; + pTree->right = 0; + } } int Patch::m_CycleCapIndex = 0; -void Patch::setDims( std::size_t w, std::size_t h ){ - if ( ( w % 2 ) == 0 ) { - w -= 1; - } - ASSERT_MESSAGE( w <= MAX_PATCH_WIDTH, "patch too wide" ); - if ( w > MAX_PATCH_WIDTH ) { - w = MAX_PATCH_WIDTH; - } - else if ( w < MIN_PATCH_WIDTH ) { - w = MIN_PATCH_WIDTH; - } - - if ( ( h % 2 ) == 0 ) { - m_height -= 1; - } - ASSERT_MESSAGE( h <= MAX_PATCH_HEIGHT, "patch too tall" ); - if ( h > MAX_PATCH_HEIGHT ) { - h = MAX_PATCH_HEIGHT; - } - else if ( h < MIN_PATCH_HEIGHT ) { - h = MIN_PATCH_HEIGHT; - } - - m_width = w; m_height = h; - - if ( m_width * m_height != m_ctrl.size() ) { - m_ctrl.resize( m_width * m_height ); - onAllocate( m_ctrl.size() ); - } -} - -inline const Colour4b& colour_for_index( std::size_t i, std::size_t width ){ - return ( i % 2 || ( i / width ) % 2 ) ? colour_inside : colour_corner; +void Patch::setDims(std::size_t w, std::size_t h) +{ + if ((w % 2) == 0) { + w -= 1; + } + ASSERT_MESSAGE(w <= MAX_PATCH_WIDTH, "patch too wide"); + if (w > MAX_PATCH_WIDTH) { + w = MAX_PATCH_WIDTH; + } else if (w < MIN_PATCH_WIDTH) { + w = MIN_PATCH_WIDTH; + } + + if ((h % 2) == 0) { + m_height -= 1; + } + ASSERT_MESSAGE(h <= MAX_PATCH_HEIGHT, "patch too tall"); + if (h > MAX_PATCH_HEIGHT) { + h = MAX_PATCH_HEIGHT; + } else if (h < MIN_PATCH_HEIGHT) { + h = MIN_PATCH_HEIGHT; + } + + m_width = w; + m_height = h; + + if (m_width * m_height != m_ctrl.size()) { + m_ctrl.resize(m_width * m_height); + onAllocate(m_ctrl.size()); + } +} + +inline const Colour4b &colour_for_index(std::size_t i, std::size_t width) +{ + return (i % 2 || (i / width) % 2) ? colour_inside : colour_corner; } -inline bool float_valid( float f ){ - return f == f; +inline bool float_valid(float f) +{ + return f == f; } -bool Patch::isValid() const { - if ( !m_width || !m_height ) { - return false; - } - - for ( const_iterator i = m_ctrl.begin(); i != m_ctrl.end(); ++i ) - { - if ( !float_valid( ( *i ).m_vertex.x() ) - || !float_valid( ( *i ).m_vertex.y() ) - || !float_valid( ( *i ).m_vertex.z() ) - || !float_valid( ( *i ).m_texcoord.x() ) - || !float_valid( ( *i ).m_texcoord.y() ) ) { - globalErrorStream() << "patch has invalid control points\n"; - return false; - } - } - return true; -} - -void Patch::UpdateCachedData(){ - m_ctrl_vertices.clear(); - m_lattice_indices.clear(); - - if ( !isValid() ) { - m_tess.m_numStrips = 0; - m_tess.m_lenStrips = 0; - m_tess.m_nArrayHeight = 0; - m_tess.m_nArrayWidth = 0; - m_tess.m_curveTreeU.resize( 0 ); - m_tess.m_curveTreeV.resize( 0 ); - m_tess.m_indices.resize( 0 ); - m_tess.m_vertices.resize( 0 ); - m_tess.m_arrayHeight.resize( 0 ); - m_tess.m_arrayWidth.resize( 0 ); - m_aabb_local = AABB(); - return; - } - - BuildTesselationCurves( ROW ); - BuildTesselationCurves( COL ); - BuildVertexArray(); - AccumulateBBox(); - - IndexBuffer ctrl_indices; - - m_lattice_indices.reserve( ( ( m_width * ( m_height - 1 ) ) + ( m_height * ( m_width - 1 ) ) ) << 1 ); - ctrl_indices.reserve( m_ctrlTransformed.size() ); - { - UniqueVertexBuffer inserter( m_ctrl_vertices ); - for ( iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i ) - { - ctrl_indices.insert( inserter.insert( pointvertex_quantised( PointVertex( reinterpret_cast( ( *i ).m_vertex ), colour_for_index( i - m_ctrlTransformed.begin(), m_width ) ) ) ) ); - } - } - { - for ( IndexBuffer::iterator i = ctrl_indices.begin(); i != ctrl_indices.end(); ++i ) - { - if ( std::size_t( i - ctrl_indices.begin() ) % m_width ) { - m_lattice_indices.insert( *( i - 1 ) ); - m_lattice_indices.insert( *i ); - } - if ( std::size_t( i - ctrl_indices.begin() ) >= m_width ) { - m_lattice_indices.insert( *( i - m_width ) ); - m_lattice_indices.insert( *i ); - } - } - } +bool Patch::isValid() const +{ + if (!m_width || !m_height) { + return false; + } + + for (const_iterator i = m_ctrl.begin(); i != m_ctrl.end(); ++i) { + if (!float_valid((*i).m_vertex.x()) + || !float_valid((*i).m_vertex.y()) + || !float_valid((*i).m_vertex.z()) + || !float_valid((*i).m_texcoord.x()) + || !float_valid((*i).m_texcoord.y())) { + globalErrorStream() << "patch has invalid control points\n"; + return false; + } + } + return true; +} + +void Patch::UpdateCachedData() +{ + m_ctrl_vertices.clear(); + m_lattice_indices.clear(); + + if (!isValid()) { + m_tess.m_numStrips = 0; + m_tess.m_lenStrips = 0; + m_tess.m_nArrayHeight = 0; + m_tess.m_nArrayWidth = 0; + m_tess.m_curveTreeU.resize(0); + m_tess.m_curveTreeV.resize(0); + m_tess.m_indices.resize(0); + m_tess.m_vertices.resize(0); + m_tess.m_arrayHeight.resize(0); + m_tess.m_arrayWidth.resize(0); + m_aabb_local = AABB(); + return; + } + + BuildTesselationCurves(ROW); + BuildTesselationCurves(COL); + BuildVertexArray(); + AccumulateBBox(); + + IndexBuffer ctrl_indices; + + m_lattice_indices.reserve(((m_width * (m_height - 1)) + (m_height * (m_width - 1))) << 1); + ctrl_indices.reserve(m_ctrlTransformed.size()); + { + UniqueVertexBuffer inserter(m_ctrl_vertices); + for (iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i) { + ctrl_indices.insert(inserter.insert(pointvertex_quantised( + PointVertex(reinterpret_cast((*i).m_vertex ), + colour_for_index(i - m_ctrlTransformed.begin(), m_width))))); + } + } + { + for (IndexBuffer::iterator i = ctrl_indices.begin(); i != ctrl_indices.end(); ++i) { + if (std::size_t(i - ctrl_indices.begin()) % m_width) { + m_lattice_indices.insert(*(i - 1)); + m_lattice_indices.insert(*i); + } + if (std::size_t(i - ctrl_indices.begin()) >= m_width) { + m_lattice_indices.insert(*(i - m_width)); + m_lattice_indices.insert(*i); + } + } + } #if 0 - { + { Array::iterator first = m_tess.m_indices.begin(); for ( std::size_t s = 0; s < m_tess.m_numStrips; s++ ) { @@ -302,286 +305,273 @@ void Patch::UpdateCachedData(){ } #endif - SceneChangeNotify(); -} - -void Patch::InvertMatrix(){ - undoSave(); - - PatchControlArray_invert( m_ctrl, m_width, m_height ); - - controlPointsChanged(); + SceneChangeNotify(); } -void Patch::TransposeMatrix(){ - undoSave(); - - { - Array tmp( m_width * m_height ); - copy_ctrl( tmp.data(), m_ctrl.data(), m_ctrl.data() + m_width * m_height ); - - PatchControlIter from = tmp.data(); - for ( std::size_t h = 0; h != m_height; ++h ) - { - PatchControlIter to = m_ctrl.data() + h; - for ( std::size_t w = 0; w != m_width; ++w, ++from, to += m_height ) - { - *to = *from; - } - } - } - - { - std::size_t tmp = m_width; - m_width = m_height; - m_height = tmp; - } - - controlPointsChanged(); -} - -void Patch::Redisperse( EMatrixMajor mt ){ - std::size_t w, h, width, height, row_stride, col_stride; - PatchControl* p1, * p2, * p3; - - undoSave(); - - switch ( mt ) - { - case COL: - width = ( m_width - 1 ) >> 1; - height = m_height; - col_stride = 1; - row_stride = m_width; - break; - case ROW: - width = ( m_height - 1 ) >> 1; - height = m_width; - col_stride = m_width; - row_stride = 1; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } - - for ( h = 0; h < height; h++ ) - { - p1 = m_ctrl.data() + ( h * row_stride ); - for ( w = 0; w < width; w++ ) - { - p2 = p1 + col_stride; - p3 = p2 + col_stride; - p2->m_vertex = vector3_mid( p1->m_vertex, p3->m_vertex ); - p1 = p3; - } - } - - controlPointsChanged(); -} - -void Patch::Smooth( EMatrixMajor mt ){ - std::size_t w, h, width, height, row_stride, col_stride; - bool wrap; - PatchControl* p1, * p2, * p3, * p2b; - - undoSave(); - - switch ( mt ) - { - case COL: - width = ( m_width - 1 ) >> 1; - height = m_height; - col_stride = 1; - row_stride = m_width; - break; - case ROW: - width = ( m_height - 1 ) >> 1; - height = m_width; - col_stride = m_width; - row_stride = 1; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } - - wrap = true; - for ( h = 0; h < height; h++ ) - { - p1 = m_ctrl.data() + ( h * row_stride ); - p2 = p1 + ( 2 * width ) * col_stride; - //globalErrorStream() << "compare " << p1->m_vertex << " and " << p2->m_vertex << "\n"; - if ( vector3_length_squared( vector3_subtracted( p1->m_vertex, p2->m_vertex ) ) > 1.0 ) { - //globalErrorStream() << "too far\n"; - wrap = false; - break; - } - } +void Patch::InvertMatrix() +{ + undoSave(); - for ( h = 0; h < height; h++ ) - { - p1 = m_ctrl.data() + ( h * row_stride ) + col_stride; - for ( w = 0; w < width - 1; w++ ) - { - p2 = p1 + col_stride; - p3 = p2 + col_stride; - p2->m_vertex = vector3_mid( p1->m_vertex, p3->m_vertex ); - p1 = p3; - } - if ( wrap ) { - p1 = m_ctrl.data() + ( h * row_stride ) + ( 2 * width - 1 ) * col_stride; - p2 = m_ctrl.data() + ( h * row_stride ); - p2b = m_ctrl.data() + ( h * row_stride ) + ( 2 * width ) * col_stride; - p3 = m_ctrl.data() + ( h * row_stride ) + col_stride; - p2->m_vertex = p2b->m_vertex = vector3_mid( p1->m_vertex, p3->m_vertex ); - } - } + PatchControlArray_invert(m_ctrl, m_width, m_height); - controlPointsChanged(); + controlPointsChanged(); } -void Patch::InsertRemove( bool bInsert, bool bColumn, bool bFirst ){ - undoSave(); - - if ( bInsert ) { - if ( bColumn && ( m_width + 2 <= MAX_PATCH_WIDTH ) ) { - InsertPoints( COL, bFirst ); - } - else if ( m_height + 2 <= MAX_PATCH_HEIGHT ) { - InsertPoints( ROW, bFirst ); - } - } - else - { - if ( bColumn && ( m_width - 2 >= MIN_PATCH_WIDTH ) ) { - RemovePoints( COL, bFirst ); - } - else if ( m_height - 2 >= MIN_PATCH_HEIGHT ) { - RemovePoints( ROW, bFirst ); - } - } +void Patch::TransposeMatrix() +{ + undoSave(); - controlPointsChanged(); -} - -Patch* Patch::MakeCap( Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst ){ - std::size_t i, width, height; - - switch ( mt ) - { - case ROW: - width = m_width; - height = m_height; - break; - case COL: - width = m_height; - height = m_width; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return 0; - } + { + Array tmp(m_width * m_height); + copy_ctrl(tmp.data(), m_ctrl.data(), m_ctrl.data() + m_width * m_height); - Array p( width ); + PatchControlIter from = tmp.data(); + for (std::size_t h = 0; h != m_height; ++h) { + PatchControlIter to = m_ctrl.data() + h; + for (std::size_t w = 0; w != m_width; ++w, ++from, to += m_height) { + *to = *from; + } + } + } - std::size_t nIndex = ( bFirst ) ? 0 : height - 1; - if ( mt == ROW ) { - for ( i = 0; i < width; i++ ) - { - p[( bFirst ) ? i : ( width - 1 ) - i] = ctrlAt( nIndex, i ).m_vertex; - } - } - else - { - for ( i = 0; i < width; i++ ) - { - p[( bFirst ) ? i : ( width - 1 ) - i] = ctrlAt( i, nIndex ).m_vertex; - } - } + { + std::size_t tmp = m_width; + m_width = m_height; + m_height = tmp; + } - patch->ConstructSeam( eType, p.data(), width ); - return patch; + controlPointsChanged(); } -void Patch::FlipTexture( int nAxis ){ - undoSave(); +void Patch::Redisperse(EMatrixMajor mt) +{ + std::size_t w, h, width, height, row_stride, col_stride; + PatchControl *p1, *p2, *p3; + + undoSave(); + + switch (mt) { + case COL: + width = (m_width - 1) >> 1; + height = m_height; + col_stride = 1; + row_stride = m_width; + break; + case ROW: + width = (m_height - 1) >> 1; + height = m_width; + col_stride = m_width; + row_stride = 1; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + + for (h = 0; h < height; h++) { + p1 = m_ctrl.data() + (h * row_stride); + for (w = 0; w < width; w++) { + p2 = p1 + col_stride; + p3 = p2 + col_stride; + p2->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex); + p1 = p3; + } + } + + controlPointsChanged(); +} + +void Patch::Smooth(EMatrixMajor mt) +{ + std::size_t w, h, width, height, row_stride, col_stride; + bool wrap; + PatchControl *p1, *p2, *p3, *p2b; + + undoSave(); + + switch (mt) { + case COL: + width = (m_width - 1) >> 1; + height = m_height; + col_stride = 1; + row_stride = m_width; + break; + case ROW: + width = (m_height - 1) >> 1; + height = m_width; + col_stride = m_width; + row_stride = 1; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + + wrap = true; + for (h = 0; h < height; h++) { + p1 = m_ctrl.data() + (h * row_stride); + p2 = p1 + (2 * width) * col_stride; + //globalErrorStream() << "compare " << p1->m_vertex << " and " << p2->m_vertex << "\n"; + if (vector3_length_squared(vector3_subtracted(p1->m_vertex, p2->m_vertex)) > 1.0) { + //globalErrorStream() << "too far\n"; + wrap = false; + break; + } + } + + for (h = 0; h < height; h++) { + p1 = m_ctrl.data() + (h * row_stride) + col_stride; + for (w = 0; w < width - 1; w++) { + p2 = p1 + col_stride; + p3 = p2 + col_stride; + p2->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex); + p1 = p3; + } + if (wrap) { + p1 = m_ctrl.data() + (h * row_stride) + (2 * width - 1) * col_stride; + p2 = m_ctrl.data() + (h * row_stride); + p2b = m_ctrl.data() + (h * row_stride) + (2 * width) * col_stride; + p3 = m_ctrl.data() + (h * row_stride) + col_stride; + p2->m_vertex = p2b->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex); + } + } + + controlPointsChanged(); +} + +void Patch::InsertRemove(bool bInsert, bool bColumn, bool bFirst) +{ + undoSave(); + + if (bInsert) { + if (bColumn && (m_width + 2 <= MAX_PATCH_WIDTH)) { + InsertPoints(COL, bFirst); + } else if (m_height + 2 <= MAX_PATCH_HEIGHT) { + InsertPoints(ROW, bFirst); + } + } else { + if (bColumn && (m_width - 2 >= MIN_PATCH_WIDTH)) { + RemovePoints(COL, bFirst); + } else if (m_height - 2 >= MIN_PATCH_HEIGHT) { + RemovePoints(ROW, bFirst); + } + } + + controlPointsChanged(); +} + +Patch *Patch::MakeCap(Patch *patch, EPatchCap eType, EMatrixMajor mt, bool bFirst) +{ + std::size_t i, width, height; + + switch (mt) { + case ROW: + width = m_width; + height = m_height; + break; + case COL: + width = m_height; + height = m_width; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return 0; + } + + Array p(width); + + std::size_t nIndex = (bFirst) ? 0 : height - 1; + if (mt == ROW) { + for (i = 0; i < width; i++) { + p[(bFirst) ? i : (width - 1) - i] = ctrlAt(nIndex, i).m_vertex; + } + } else { + for (i = 0; i < width; i++) { + p[(bFirst) ? i : (width - 1) - i] = ctrlAt(i, nIndex).m_vertex; + } + } + + patch->ConstructSeam(eType, p.data(), width); + return patch; +} + +void Patch::FlipTexture(int nAxis) +{ + undoSave(); - for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i ) - { - ( *i ).m_texcoord[nAxis] = -( *i ).m_texcoord[nAxis]; - } + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + (*i).m_texcoord[nAxis] = -(*i).m_texcoord[nAxis]; + } - controlPointsChanged(); + controlPointsChanged(); } -void Patch::TranslateTexture( float s, float t ){ - undoSave(); +void Patch::TranslateTexture(float s, float t) +{ + undoSave(); - s = -1 * s / m_state->getTexture().width; - t = t / m_state->getTexture().height; + s = -1 * s / m_state->getTexture().width; + t = t / m_state->getTexture().height; - for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i ) - { - ( *i ).m_texcoord[0] += s; - ( *i ).m_texcoord[1] += t; - } + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + (*i).m_texcoord[0] += s; + (*i).m_texcoord[1] += t; + } - controlPointsChanged(); + controlPointsChanged(); } -void Patch::ScaleTexture( float s, float t ){ - undoSave(); +void Patch::ScaleTexture(float s, float t) +{ + undoSave(); - for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i ) - { - ( *i ).m_texcoord[0] *= s; - ( *i ).m_texcoord[1] *= t; - } + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + (*i).m_texcoord[0] *= s; + (*i).m_texcoord[1] *= t; + } - controlPointsChanged(); + controlPointsChanged(); } -void Patch::RotateTexture( float angle ){ - undoSave(); +void Patch::RotateTexture(float angle) +{ + undoSave(); - const float s = static_cast( sin( degrees_to_radians( angle ) ) ); - const float c = static_cast( cos( degrees_to_radians( angle ) ) ); + const float s = static_cast( sin(degrees_to_radians(angle))); + const float c = static_cast( cos(degrees_to_radians(angle))); - for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i ) - { - const float x = ( *i ).m_texcoord[0]; - const float y = ( *i ).m_texcoord[1]; - ( *i ).m_texcoord[0] = ( x * c ) - ( y * s ); - ( *i ).m_texcoord[1] = ( y * c ) + ( x * s ); - } + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + const float x = (*i).m_texcoord[0]; + const float y = (*i).m_texcoord[1]; + (*i).m_texcoord[0] = (x * c) - (y * s); + (*i).m_texcoord[1] = (y * c) + (x * s); + } - controlPointsChanged(); + controlPointsChanged(); } -void Patch::SetTextureRepeat( float s, float t ){ - std::size_t w, h; - float si, ti, sc, tc; - PatchControl *pDest; +void Patch::SetTextureRepeat(float s, float t) +{ + std::size_t w, h; + float si, ti, sc, tc; + PatchControl *pDest; - undoSave(); + undoSave(); - si = s / (float)( m_width - 1 ); - ti = t / (float)( m_height - 1 ); + si = s / (float) (m_width - 1); + ti = t / (float) (m_height - 1); - pDest = m_ctrl.data(); - for ( h = 0, tc = 0.0f; h < m_height; h++, tc += ti ) - { - for ( w = 0, sc = 0.0f; w < m_width; w++, sc += si ) - { - pDest->m_texcoord[0] = sc; - pDest->m_texcoord[1] = tc; - pDest++; - } - } + pDest = m_ctrl.data(); + for (h = 0, tc = 0.0f; h < m_height; h++, tc += ti) { + for (w = 0, sc = 0.0f; w < m_width; w++, sc += si) { + pDest->m_texcoord[0] = sc; + pDest->m_texcoord[1] = tc; + pDest++; + } + } - controlPointsChanged(); + controlPointsChanged(); } /* @@ -600,158 +590,159 @@ void Patch::SetTextureRepeat( float s, float t ){ } */ -inline int texture_axis( const Vector3& normal ){ - // axis dominance order: Z, X, Y - return ( normal.x() >= normal.y() ) ? ( normal.x() > normal.z() ) ? 0 : 2 : ( normal.y() > normal.z() ) ? 1 : 2; +inline int texture_axis(const Vector3 &normal) +{ + // axis dominance order: Z, X, Y + return (normal.x() >= normal.y()) ? (normal.x() > normal.z()) ? 0 : 2 : (normal.y() > normal.z()) ? 1 : 2; } -void Patch::CapTexture(){ - const PatchControl& p1 = m_ctrl[m_width]; - const PatchControl& p2 = m_ctrl[m_width * ( m_height - 1 )]; - const PatchControl& p3 = m_ctrl[( m_width * m_height ) - 1]; - - - Vector3 normal( g_vector3_identity ); - - { - Vector3 tmp( vector3_cross( - vector3_subtracted( p2.m_vertex, m_ctrl[0].m_vertex ), - vector3_subtracted( p3.m_vertex, m_ctrl[0].m_vertex ) - ) ); - if ( !vector3_equal( tmp, g_vector3_identity ) ) { - vector3_add( normal, tmp ); - } - } - { - Vector3 tmp( vector3_cross( - vector3_subtracted( p1.m_vertex, p3.m_vertex ), - vector3_subtracted( m_ctrl[0].m_vertex, p3.m_vertex ) - ) ); - if ( !vector3_equal( tmp, g_vector3_identity ) ) { - vector3_add( normal, tmp ); - } - } - - ProjectTexture( texture_axis( normal ) ); +void Patch::CapTexture() +{ + const PatchControl &p1 = m_ctrl[m_width]; + const PatchControl &p2 = m_ctrl[m_width * (m_height - 1)]; + const PatchControl &p3 = m_ctrl[(m_width * m_height) - 1]; + + + Vector3 normal(g_vector3_identity); + + { + Vector3 tmp(vector3_cross( + vector3_subtracted(p2.m_vertex, m_ctrl[0].m_vertex), + vector3_subtracted(p3.m_vertex, m_ctrl[0].m_vertex) + )); + if (!vector3_equal(tmp, g_vector3_identity)) { + vector3_add(normal, tmp); + } + } + { + Vector3 tmp(vector3_cross( + vector3_subtracted(p1.m_vertex, p3.m_vertex), + vector3_subtracted(m_ctrl[0].m_vertex, p3.m_vertex) + )); + if (!vector3_equal(tmp, g_vector3_identity)) { + vector3_add(normal, tmp); + } + } + + ProjectTexture(texture_axis(normal)); } // uses longest parallel chord to calculate texture coords for each row/col -void Patch::NaturalTexture(){ - undoSave(); - - { - float fSize = (float)m_state->getTexture().width * Texdef_getDefaultTextureScale(); - - double texBest = 0; - double tex = 0; - PatchControl* pWidth = m_ctrl.data(); - for ( std::size_t w = 0; w < m_width; w++, pWidth++ ) - { - { - PatchControl* pHeight = pWidth; - for ( std::size_t h = 0; h < m_height; h++, pHeight += m_width ) - pHeight->m_texcoord[0] = static_cast( tex ); - } - - if ( w + 1 == m_width ) { - break; - } - - { - PatchControl* pHeight = pWidth; - for ( std::size_t h = 0; h < m_height; h++, pHeight += m_width ) - { - Vector3 v( vector3_subtracted( pHeight->m_vertex, ( pHeight + 1 )->m_vertex ) ); - double length = tex + ( vector3_length( v ) / fSize ); - if ( fabs( length ) > texBest ) { - texBest = length; - } - } - } - - tex = texBest; - } - } - - { - float fSize = -(float)m_state->getTexture().height * Texdef_getDefaultTextureScale(); - - double texBest = 0; - double tex = 0; - PatchControl* pHeight = m_ctrl.data(); - for ( std::size_t h = 0; h < m_height; h++, pHeight += m_width ) - { - { - PatchControl* pWidth = pHeight; - for ( std::size_t w = 0; w < m_width; w++, pWidth++ ) - pWidth->m_texcoord[1] = static_cast( tex ); - } - - if ( h + 1 == m_height ) { - break; - } - - { - PatchControl* pWidth = pHeight; - for ( std::size_t w = 0; w < m_width; w++, pWidth++ ) - { - Vector3 v( vector3_subtracted( pWidth->m_vertex, ( pWidth + m_width )->m_vertex ) ); - double length = tex + ( vector3_length( v ) / fSize ); - if ( fabs( length ) > texBest ) { - texBest = length; - } - } - } - - tex = texBest; - } - } - - controlPointsChanged(); +void Patch::NaturalTexture() +{ + undoSave(); + + { + float fSize = (float) m_state->getTexture().width * Texdef_getDefaultTextureScale(); + + double texBest = 0; + double tex = 0; + PatchControl *pWidth = m_ctrl.data(); + for (std::size_t w = 0; w < m_width; w++, pWidth++) { + { + PatchControl *pHeight = pWidth; + for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) { + pHeight->m_texcoord[0] = static_cast( tex ); + } + } + + if (w + 1 == m_width) { + break; + } + + { + PatchControl *pHeight = pWidth; + for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) { + Vector3 v(vector3_subtracted(pHeight->m_vertex, (pHeight + 1)->m_vertex)); + double length = tex + (vector3_length(v) / fSize); + if (fabs(length) > texBest) { + texBest = length; + } + } + } + + tex = texBest; + } + } + + { + float fSize = -(float) m_state->getTexture().height * Texdef_getDefaultTextureScale(); + + double texBest = 0; + double tex = 0; + PatchControl *pHeight = m_ctrl.data(); + for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) { + { + PatchControl *pWidth = pHeight; + for (std::size_t w = 0; w < m_width; w++, pWidth++) { + pWidth->m_texcoord[1] = static_cast( tex ); + } + } + + if (h + 1 == m_height) { + break; + } + + { + PatchControl *pWidth = pHeight; + for (std::size_t w = 0; w < m_width; w++, pWidth++) { + Vector3 v(vector3_subtracted(pWidth->m_vertex, (pWidth + m_width)->m_vertex)); + double length = tex + (vector3_length(v) / fSize); + if (fabs(length) > texBest) { + texBest = length; + } + } + } + + tex = texBest; + } + } + + controlPointsChanged(); } // private: -void Patch::AccumulateBBox(){ - m_aabb_local = AABB(); +void Patch::AccumulateBBox() +{ + m_aabb_local = AABB(); - for ( PatchControlArray::iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i ) - { - aabb_extend_by_point_safe( m_aabb_local, ( *i ).m_vertex ); - } + for (PatchControlArray::iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i) { + aabb_extend_by_point_safe(m_aabb_local, (*i).m_vertex); + } - m_boundsChanged(); - m_lightsChanged(); -} - -void Patch::InsertPoints( EMatrixMajor mt, bool bFirst ){ - std::size_t width, height, row_stride, col_stride; - - switch ( mt ) - { - case ROW: - col_stride = 1; - row_stride = m_width; - width = m_width; - height = m_height; - break; - case COL: - col_stride = m_width; - row_stride = 1; - width = m_height; - height = m_width; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } + m_boundsChanged(); + m_lightsChanged(); +} - std::size_t pos = 0; - { - PatchControl* p1 = m_ctrl.data(); - /* +void Patch::InsertPoints(EMatrixMajor mt, bool bFirst) +{ + std::size_t width, height, row_stride, col_stride; + + switch (mt) { + case ROW: + col_stride = 1; + row_stride = m_width; + width = m_width; + height = m_height; + break; + case COL: + col_stride = m_width; + row_stride = 1; + width = m_height; + height = m_width; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + + std::size_t pos = 0; + { + PatchControl *p1 = m_ctrl.data(); + /* if(GlobalSelectionSystem().countSelected() != 0) { scene::Instance& instance = GlobalSelectionSystem().ultimateSelected(); @@ -759,2060 +750,2009 @@ void Patch::InsertPoints( EMatrixMajor mt, bool bFirst ){ patch->m_selectable.isSelected(); } */ - for ( std::size_t w = 0; w != width; ++w, p1 += col_stride ) - { - { - PatchControl* p2 = p1; - for ( std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride ) - { - if ( 0 ) { //p2->m_selectable.isSelected()) - pos = h; - break; - } - } - if ( pos != 0 ) { - break; - } - } + for (std::size_t w = 0; w != width; ++w, p1 += col_stride) { + { + PatchControl *p2 = p1; + for (std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride) { + if (0) { //p2->m_selectable.isSelected()) + pos = h; + break; + } + } + if (pos != 0) { + break; + } + } + + { + PatchControl *p2 = p1; + for (std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride) { + if (0) { //p2->m_selectable.isSelected()) + pos = h; + break; + } + } + if (pos != 0) { + break; + } + } + } + } + + Array tmp(m_ctrl); + + std::size_t row_stride2, col_stride2; + switch (mt) { + case ROW: + setDims(m_width, m_height + 2); + col_stride2 = 1; + row_stride2 = m_width; + break; + case COL: + setDims(m_width + 2, m_height); + col_stride2 = m_width; + row_stride2 = 1; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + if (bFirst) { + pos = height - 1; + } else { + pos = 2; + } + + if (pos >= height) { + if (bFirst) { + pos = height - 1; + } else { + pos = 2; + } + } else if (pos == 0) { + pos = 2; + } else if (pos % 2) { + ++pos; + } + + + for (std::size_t w = 0; w != width; ++w) { + PatchControl *p1 = tmp.data() + (w * col_stride); + PatchControl *p2 = m_ctrl.data() + (w * col_stride2); + for (std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride) { + if (h == pos) { + p2 += 2 * row_stride2; + } + *p2 = *p1; + } + + p1 = tmp.data() + (w * col_stride + pos * row_stride); + p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2); + + PatchControl *r2a = (p2 + row_stride2); + PatchControl *r2b = (p2 - row_stride2); + PatchControl *c2a = (p1 - 2 * row_stride); + PatchControl *c2b = (p1 - row_stride); + + // set two new row points + *(p2 + 2 * row_stride2) = *p1; + *r2a = *c2b; + + for (std::size_t i = 0; i != 3; ++i) { + r2a->m_vertex[i] = float_mid(c2b->m_vertex[i], p1->m_vertex[i]); + + r2b->m_vertex[i] = float_mid(c2a->m_vertex[i], c2b->m_vertex[i]); + + p2->m_vertex[i] = float_mid(r2a->m_vertex[i], r2b->m_vertex[i]); + } + for (std::size_t i = 0; i != 2; ++i) { + r2a->m_texcoord[i] = float_mid(c2b->m_texcoord[i], p1->m_texcoord[i]); + + r2b->m_texcoord[i] = float_mid(c2a->m_texcoord[i], c2b->m_texcoord[i]); + + p2->m_texcoord[i] = float_mid(r2a->m_texcoord[i], r2b->m_texcoord[i]); + } + } +} + +void Patch::RemovePoints(EMatrixMajor mt, bool bFirst) +{ + std::size_t width, height, row_stride, col_stride; + + switch (mt) { + case ROW: + col_stride = 1; + row_stride = m_width; + width = m_width; + height = m_height; + break; + case COL: + col_stride = m_width; + row_stride = 1; + width = m_height; + height = m_width; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + + std::size_t pos = 0; + { + PatchControl *p1 = m_ctrl.data(); + for (std::size_t w = 0; w != width; ++w, p1 += col_stride) { + { + PatchControl *p2 = p1; + for (std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride) { + if (0) { //p2->m_selectable.isSelected()) + pos = h; + break; + } + } + if (pos != 0) { + break; + } + } + + { + PatchControl *p2 = p1; + for (std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride) { + if (0) { //p2->m_selectable.isSelected()) + pos = h; + break; + } + } + if (pos != 0) { + break; + } + } + } + } + + Array tmp(m_ctrl); + + std::size_t row_stride2, col_stride2; + switch (mt) { + case ROW: + setDims(m_width, m_height - 2); + col_stride2 = 1; + row_stride2 = m_width; + break; + case COL: + setDims(m_width - 2, m_height); + col_stride2 = m_width; + row_stride2 = 1; + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + if (bFirst) { + pos = height - 3; + } else { + pos = 2; + } + if (pos >= height) { + if (bFirst) { + pos = height - 3; + } else { + pos = 2; + } + } else if (pos == 0) { + pos = 2; + } else if (pos > height - 3) { + pos = height - 3; + } else if (pos % 2) { + ++pos; + } + + for (std::size_t w = 0; w != width; w++) { + PatchControl *p1 = tmp.data() + (w * col_stride); + PatchControl *p2 = m_ctrl.data() + (w * col_stride2); + for (std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride) { + if (h == pos) { + p1 += 2 * row_stride2; + h += 2; + } + *p2 = *p1; + } + + p1 = tmp.data() + (w * col_stride + pos * row_stride); + p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2); + + for (std::size_t i = 0; i < 3; i++) { + (p2 - row_stride2)->m_vertex[i] = + ((p1 + 2 * row_stride)->m_vertex[i] + (p1 - 2 * row_stride)->m_vertex[i]) * 0.5f; + + (p2 - row_stride2)->m_vertex[i] = + (p2 - row_stride2)->m_vertex[i] + (2.0f * ((p1)->m_vertex[i] - (p2 - row_stride2)->m_vertex[i])); + } + for (std::size_t i = 0; i < 2; i++) { + (p2 - row_stride2)->m_texcoord[i] = + ((p1 + 2 * row_stride)->m_texcoord[i] + (p1 - 2 * row_stride)->m_texcoord[i]) * 0.5f; + + (p2 - row_stride2)->m_texcoord[i] = (p2 - row_stride2)->m_texcoord[i] + + (2.0f * ((p1)->m_texcoord[i] - (p2 - row_stride2)->m_texcoord[i])); + } + } +} + +void Patch::ConstructSeam(EPatchCap eType, Vector3 *p, std::size_t width) +{ + switch (eType) { + case eCapIBevel: { + setDims(3, 3); + m_ctrl[0].m_vertex = p[0]; + m_ctrl[1].m_vertex = p[1]; + m_ctrl[2].m_vertex = p[1]; + m_ctrl[3].m_vertex = p[1]; + m_ctrl[4].m_vertex = p[1]; + m_ctrl[5].m_vertex = p[1]; + m_ctrl[6].m_vertex = p[2]; + m_ctrl[7].m_vertex = p[1]; + m_ctrl[8].m_vertex = p[1]; + } + break; + case eCapBevel: { + setDims(3, 3); + Vector3 p3(vector3_added(p[2], vector3_subtracted(p[0], p[1]))); + m_ctrl[0].m_vertex = p3; + m_ctrl[1].m_vertex = p3; + m_ctrl[2].m_vertex = p[2]; + m_ctrl[3].m_vertex = p3; + m_ctrl[4].m_vertex = p3; + m_ctrl[5].m_vertex = p[1]; + m_ctrl[6].m_vertex = p3; + m_ctrl[7].m_vertex = p3; + m_ctrl[8].m_vertex = p[0]; + } + break; + case eCapEndCap: { + Vector3 p5(vector3_mid(p[0], p[4])); + + setDims(3, 3); + m_ctrl[0].m_vertex = p[0]; + m_ctrl[1].m_vertex = p5; + m_ctrl[2].m_vertex = p[4]; + m_ctrl[3].m_vertex = p[1]; + m_ctrl[4].m_vertex = p[2]; + m_ctrl[5].m_vertex = p[3]; + m_ctrl[6].m_vertex = p[2]; + m_ctrl[7].m_vertex = p[2]; + m_ctrl[8].m_vertex = p[2]; + } + break; + case eCapIEndCap: { + setDims(5, 3); + m_ctrl[0].m_vertex = p[4]; + m_ctrl[1].m_vertex = p[3]; + m_ctrl[2].m_vertex = p[2]; + m_ctrl[3].m_vertex = p[1]; + m_ctrl[4].m_vertex = p[0]; + m_ctrl[5].m_vertex = p[3]; + m_ctrl[6].m_vertex = p[3]; + m_ctrl[7].m_vertex = p[2]; + m_ctrl[8].m_vertex = p[1]; + m_ctrl[9].m_vertex = p[1]; + m_ctrl[10].m_vertex = p[3]; + m_ctrl[11].m_vertex = p[3]; + m_ctrl[12].m_vertex = p[2]; + m_ctrl[13].m_vertex = p[1]; + m_ctrl[14].m_vertex = p[1]; + } + break; + case eCapCylinder: { + std::size_t mid = (width - 1) >> 1; + + bool degenerate = (mid % 2) != 0; + + std::size_t newHeight = mid + (degenerate ? 2 : 1); + + setDims(3, newHeight); + + if (degenerate) { + ++mid; + for (std::size_t i = width; i != width + 2; ++i) { + p[i] = p[width - 1]; + } + } + + { + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t i = 0; i != m_height; ++i, pCtrl += m_width) { + pCtrl->m_vertex = p[i]; + } + } + { + PatchControl *pCtrl = m_ctrl.data() + 2; + std::size_t h = m_height - 1; + for (std::size_t i = 0; i != m_height; ++i, pCtrl += m_width) { + pCtrl->m_vertex = p[h + (h - i)]; + } + } + + Redisperse(COL); + } + break; + default: + ERROR_MESSAGE("invalid patch-cap type"); + return; + } + CapTexture(); + controlPointsChanged(); +} + +void Patch::ProjectTexture(int nAxis) +{ + undoSave(); + + int s, t; + + switch (nAxis) { + case 2: + s = 0; + t = 1; + break; + case 0: + s = 1; + t = 2; + break; + case 1: + s = 0; + t = 2; + break; + default: + ERROR_MESSAGE("invalid axis"); + return; + } + + float fWidth = 1 / (m_state->getTexture().width * Texdef_getDefaultTextureScale()); + float fHeight = 1 / (m_state->getTexture().height * -Texdef_getDefaultTextureScale()); + + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + (*i).m_texcoord[0] = (*i).m_vertex[s] * fWidth; + (*i).m_texcoord[1] = (*i).m_vertex[t] * fHeight; + } + + controlPointsChanged(); +} + +void Patch::constructPlane(const AABB &aabb, int axis, std::size_t width, std::size_t height) +{ + setDims(width, height); + + int x, y, z; + switch (axis) { + case 2: + x = 0; + y = 1; + z = 2; + break; + case 1: + x = 0; + y = 2; + z = 1; + break; + case 0: + x = 1; + y = 2; + z = 0; + break; + default: + ERROR_MESSAGE("invalid view-type"); + return; + } + + if (m_width < MIN_PATCH_WIDTH || m_width > MAX_PATCH_WIDTH) { + m_width = 3; + } + if (m_height < MIN_PATCH_HEIGHT || m_height > MAX_PATCH_HEIGHT) { + m_height = 3; + } + + Vector3 vStart; + vStart[x] = aabb.origin[x] - aabb.extents[x]; + vStart[y] = aabb.origin[y] - aabb.extents[y]; + vStart[z] = aabb.origin[z]; + + float xAdj = fabsf((vStart[x] - (aabb.origin[x] + aabb.extents[x])) / (float) (m_width - 1)); + float yAdj = fabsf((vStart[y] - (aabb.origin[y] + aabb.extents[y])) / (float) (m_height - 1)); + + Vector3 vTmp; + vTmp[z] = vStart[z]; + PatchControl *pCtrl = m_ctrl.data(); + + vTmp[y] = vStart[y]; + for (std::size_t h = 0; h < m_height; h++) { + vTmp[x] = vStart[x]; + for (std::size_t w = 0; w < m_width; w++, ++pCtrl) { + pCtrl->m_vertex = vTmp; + vTmp[x] += xAdj; + } + vTmp[y] += yAdj; + } + + NaturalTexture(); +} + +void Patch::ConstructPrefab(const AABB &aabb, EPatchPrefab eType, int axis, std::size_t width, std::size_t height) +{ + Vector3 vPos[3]; + + if (eType != ePlane) { + vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + vPos[1] = aabb.origin; + vPos[2] = vector3_added(aabb.origin, aabb.extents); + } + + if (eType == ePlane) { + constructPlane(aabb, axis, width, height); + } else if (eType == eSqCylinder + || eType == eCylinder + || eType == eDenseCylinder + || eType == eVeryDenseCylinder + || eType == eCone + || eType == eSphere) { + unsigned char *pIndex; + unsigned char pCylIndex[] = + { + 0, 0, + 1, 0, + 2, 0, + 2, 1, + 2, 2, + 1, 2, + 0, 2, + 0, 1, + 0, 0 + }; + + + PatchControl *pStart; + switch (eType) { + case eSqCylinder: + setDims(9, 3); + pStart = m_ctrl.data(); + break; + case eDenseCylinder: + case eVeryDenseCylinder: + case eCylinder: + setDims(9, 3); + pStart = m_ctrl.data() + 1; + break; + case eCone: + setDims(9, 3); + pStart = m_ctrl.data() + 1; + break; + case eSphere: + setDims(9, 5); + pStart = m_ctrl.data() + (9 + 1); + break; + default: + ERROR_MESSAGE("this should be unreachable"); + return; + } + + for (std::size_t h = 0; h < 3; h++, pStart += 9) { + pIndex = pCylIndex; + PatchControl *pCtrl = pStart; + for (std::size_t w = 0; w < 8; w++, pCtrl++) { + pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; + pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; + pCtrl->m_vertex[2] = vPos[h][2]; + pIndex += 2; + } + } + + switch (eType) { + case eSqCylinder: { + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t h = 0; h < 3; h++, pCtrl += 9) { + pCtrl[8].m_vertex = pCtrl[0].m_vertex; + } + } + break; + case eDenseCylinder: + case eVeryDenseCylinder: + case eCylinder: { + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t h = 0; h < 3; h++, pCtrl += 9) { + pCtrl[0].m_vertex = pCtrl[8].m_vertex; + } + } + break; + case eCone: { + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t h = 0; h < 2; h++, pCtrl += 9) { + pCtrl[0].m_vertex = pCtrl[8].m_vertex; + } + } + { + PatchControl *pCtrl = m_ctrl.data() + 9 * 2; + for (std::size_t w = 0; w < 9; w++, pCtrl++) { + pCtrl->m_vertex[0] = vPos[1][0]; + pCtrl->m_vertex[1] = vPos[1][1]; + pCtrl->m_vertex[2] = vPos[2][2]; + } + } + break; + case eSphere: { + PatchControl *pCtrl = m_ctrl.data() + 9; + for (std::size_t h = 0; h < 3; h++, pCtrl += 9) { + pCtrl[0].m_vertex = pCtrl[8].m_vertex; + } + } + { + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t w = 0; w < 9; w++, pCtrl++) { + pCtrl->m_vertex[0] = vPos[1][0]; + pCtrl->m_vertex[1] = vPos[1][1]; + pCtrl->m_vertex[2] = vPos[0][2]; + } + } + { + PatchControl *pCtrl = m_ctrl.data() + (9 * 4); + for (std::size_t w = 0; w < 9; w++, pCtrl++) { + pCtrl->m_vertex[0] = vPos[1][0]; + pCtrl->m_vertex[1] = vPos[1][1]; + pCtrl->m_vertex[2] = vPos[2][2]; + } + } + break; + default: + ERROR_MESSAGE("this should be unreachable"); + return; + } + } else if (eType == eXactCylinder) { + int n = (width - 1) / 2; // n = number of segments + setDims(width, height); + + // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + // vPos[1] = aabb.origin; + // vPos[2] = vector3_added(aabb.origin, aabb.extents); + + float f = 1 / cos(M_PI / n); + for (std::size_t i = 0; i < width; ++i) { + float angle = (M_PI * i) / n; // 0 to 2pi + float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * cos(angle) * ((i & 1) ? f : 1.0f); + float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle) * ((i & 1) ? f : 1.0f); + for (std::size_t j = 0; j < height; ++j) { + float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float) (height - 1)); + PatchControl *v; + v = &m_ctrl.data()[j * width + i]; + v->m_vertex[0] = x; + v->m_vertex[1] = y; + v->m_vertex[2] = z; + } + } + } else if (eType == eXactCone) { + int n = (width - 1) / 2; // n = number of segments + setDims(width, height); + + // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + // vPos[1] = aabb.origin; + // vPos[2] = vector3_added(aabb.origin, aabb.extents); + + float f = 1 / cos(M_PI / n); + for (std::size_t i = 0; i < width; ++i) { + float angle = (M_PI * i) / n; + for (std::size_t j = 0; j < height; ++j) { + float x = vPos[1][0] + (1.0f - (j / (float) (height - 1))) * (vPos[2][0] - vPos[1][0]) * cos(angle) * + ((i & 1) ? f : 1.0f); + float y = vPos[1][1] + (1.0f - (j / (float) (height - 1))) * (vPos[2][1] - vPos[1][1]) * sin(angle) * + ((i & 1) ? f : 1.0f); + float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float) (height - 1)); + PatchControl *v; + v = &m_ctrl.data()[j * width + i]; + v->m_vertex[0] = x; + v->m_vertex[1] = y; + v->m_vertex[2] = z; + } + } + } else if (eType == eXactSphere) { + int n = (width - 1) / 2; // n = number of segments (yaw) + int m = (height - 1) / 2; // m = number of segments (pitch) + setDims(width, height); + + // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + // vPos[1] = aabb.origin; + // vPos[2] = vector3_added(aabb.origin, aabb.extents); + + float f = 1 / cos(M_PI / n); + float g = 1 / cos(M_PI / (2 * m)); + for (std::size_t i = 0; i < width; ++i) { + float angle = (M_PI * i) / n; + for (std::size_t j = 0; j < height; ++j) { + float angle2 = (M_PI * j) / (2 * m); + float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * sin(angle2) * ((j & 1) ? g : 1.0f) * cos(angle) * + ((i & 1) ? f : 1.0f); + float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle2) * ((j & 1) ? g : 1.0f) * sin(angle) * + ((i & 1) ? f : 1.0f); + float z = vPos[1][2] + (vPos[2][2] - vPos[1][2]) * -cos(angle2) * ((j & 1) ? g : 1.0f); + PatchControl *v; + v = &m_ctrl.data()[j * width + i]; + v->m_vertex[0] = x; + v->m_vertex[1] = y; + v->m_vertex[2] = z; + } + } + } else if (eType == eBevel) { + unsigned char *pIndex; + unsigned char pBevIndex[] = + { + 0, 0, + 2, 0, + 2, 2, + }; + + setDims(3, 3); + + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t h = 0; h < 3; h++) { + pIndex = pBevIndex; + for (std::size_t w = 0; w < 3; w++, pIndex += 2, pCtrl++) { + pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; + pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; + pCtrl->m_vertex[2] = vPos[h][2]; + } + } + } else if (eType == eEndCap) { + unsigned char *pIndex; + unsigned char pEndIndex[] = + { + 2, 0, + 2, 2, + 1, 2, + 0, 2, + 0, 0, + }; + + setDims(5, 3); + + PatchControl *pCtrl = m_ctrl.data(); + for (std::size_t h = 0; h < 3; h++) { + pIndex = pEndIndex; + for (std::size_t w = 0; w < 5; w++, pIndex += 2, pCtrl++) { + pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; + pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; + pCtrl->m_vertex[2] = vPos[h][2]; + } + } + } + + if (eType == eDenseCylinder) { + InsertRemove(true, false, true); + } + + if (eType == eVeryDenseCylinder) { + InsertRemove(true, false, false); + InsertRemove(true, false, true); + } + + NaturalTexture(); +} + +void Patch::RenderDebug(RenderStateFlags state) const +{ + for (std::size_t i = 0; i < m_tess.m_numStrips; i++) { + glBegin(GL_QUAD_STRIP); + for (std::size_t j = 0; j < m_tess.m_lenStrips; j++) { + glNormal3fv(normal3f_to_array( + (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->normal)); + glTexCoord2fv(texcoord2f_to_array( + (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->texcoord)); + glVertex3fv(vertex3f_to_array( + (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->vertex)); + } + glEnd(); + } +} + +void RenderablePatchSolid::RenderNormals() const +{ + const std::size_t width = m_tess.m_numStrips + 1; + const std::size_t height = m_tess.m_lenStrips >> 1; + glBegin(GL_LINES); + for (std::size_t i = 0; i < width; i++) { + for (std::size_t j = 0; j < height; j++) { + { + Vector3 vNormal( + vector3_added( + vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex), + vector3_scaled( + normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->normal), 8) + ) + ); + glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex)); + glVertex3fv(&vNormal[0]); + } + { + Vector3 vNormal( + vector3_added( + vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex), + vector3_scaled( + normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->tangent), 8) + ) + ); + glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex)); + glVertex3fv(&vNormal[0]); + } + { + Vector3 vNormal( + vector3_added( + vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex), + vector3_scaled( + normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->bitangent), 8) + ) + ); + glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex)); + glVertex3fv(&vNormal[0]); + } + } + } + glEnd(); +} + +const int DEGEN_0a = 0x01; +const int DEGEN_1a = 0x02; +const int DEGEN_2a = 0x04; +const int DEGEN_0b = 0x08; +const int DEGEN_1b = 0x10; +const int DEGEN_2b = 0x20; +const int SPLIT = 0x40; +const int AVERAGE = 0x80; + + +unsigned int subarray_get_degen(PatchControlIter subarray, std::size_t strideU, std::size_t strideV) +{ + unsigned int nDegen = 0; + const PatchControl *p1; + const PatchControl *p2; + + p1 = subarray; + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_0a; + } + p1 = p2; + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_0b; + } + + p1 = subarray + strideV; + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_1a; + } + p1 = p2; + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_1b; + } + + p1 = subarray + (strideV << 1); + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_2a; + } + p1 = p2; + p2 = p1 + strideU; + if (vector3_equal(p1->m_vertex, p2->m_vertex)) { + nDegen |= DEGEN_2b; + } + + return nDegen; +} + + +inline void +deCasteljau3(const Vector3 &P0, const Vector3 &P1, const Vector3 &P2, Vector3 &P01, Vector3 &P12, Vector3 &P012) +{ + P01 = vector3_mid(P0, P1); + P12 = vector3_mid(P1, P2); + P012 = vector3_mid(P01, P12); +} - { - PatchControl* p2 = p1; - for ( std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride ) - { - if ( 0 ) { //p2->m_selectable.isSelected()) - pos = h; - break; - } - } - if ( pos != 0 ) { - break; - } - } - } - } +inline void BezierInterpolate3(const Vector3 &start, Vector3 &left, Vector3 &mid, Vector3 &right, const Vector3 &end) +{ + left = vector3_mid(start, mid); + right = vector3_mid(mid, end); + mid = vector3_mid(left, right); +} - Array tmp( m_ctrl ); - - std::size_t row_stride2, col_stride2; - switch ( mt ) - { - case ROW: - setDims( m_width, m_height + 2 ); - col_stride2 = 1; - row_stride2 = m_width; - break; - case COL: - setDims( m_width + 2, m_height ); - col_stride2 = m_width; - row_stride2 = 1; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } - if ( bFirst ) { - pos = height - 1; - } - else - { - pos = 2; - } +inline void BezierInterpolate2(const Vector2 &start, Vector2 &left, Vector2 &mid, Vector2 &right, const Vector2 &end) +{ + left[0] = float_mid(start[0], mid[0]); + left[1] = float_mid(start[1], mid[1]); + right[0] = float_mid(mid[0], end[0]); + right[1] = float_mid(mid[1], end[1]); + mid[0] = float_mid(left[0], right[0]); + mid[1] = float_mid(left[1], right[1]); +} - if ( pos >= height ) { - if ( bFirst ) { - pos = height - 1; - } - else - { - pos = 2; - } - } - else if ( pos == 0 ) { - pos = 2; - } - else if ( pos % 2 ) { - ++pos; - } +inline Vector2 &texcoord_for_index(Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].texcoord ); +} - for ( std::size_t w = 0; w != width; ++w ) - { - PatchControl* p1 = tmp.data() + ( w * col_stride ); - PatchControl* p2 = m_ctrl.data() + ( w * col_stride2 ); - for ( std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride ) - { - if ( h == pos ) { - p2 += 2 * row_stride2; - } - *p2 = *p1; - } +inline Vector3 &vertex_for_index(Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].vertex ); +} - p1 = tmp.data() + ( w * col_stride + pos * row_stride ); - p2 = m_ctrl.data() + ( w * col_stride2 + pos * row_stride2 ); +inline Vector3 &normal_for_index(Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].normal ); +} - PatchControl* r2a = ( p2 + row_stride2 ); - PatchControl* r2b = ( p2 - row_stride2 ); - PatchControl* c2a = ( p1 - 2 * row_stride ); - PatchControl* c2b = ( p1 - row_stride ); +inline Vector3 &tangent_for_index(Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].tangent ); +} - // set two new row points - *( p2 + 2 * row_stride2 ) = *p1; - *r2a = *c2b; +inline Vector3 &bitangent_for_index(Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].bitangent ); +} - for ( std::size_t i = 0; i != 3; ++i ) - { - r2a->m_vertex[i] = float_mid( c2b->m_vertex[i], p1->m_vertex[i] ); +inline const Vector2 &texcoord_for_index(const Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].texcoord ); +} - r2b->m_vertex[i] = float_mid( c2a->m_vertex[i], c2b->m_vertex[i] ); +inline const Vector3 &vertex_for_index(const Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].vertex ); +} - p2->m_vertex[i] = float_mid( r2a->m_vertex[i], r2b->m_vertex[i] ); - } - for ( std::size_t i = 0; i != 2; ++i ) - { - r2a->m_texcoord[i] = float_mid( c2b->m_texcoord[i], p1->m_texcoord[i] ); +inline const Vector3 &normal_for_index(const Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].normal ); +} - r2b->m_texcoord[i] = float_mid( c2a->m_texcoord[i], c2b->m_texcoord[i] ); +inline const Vector3 &tangent_for_index(const Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].tangent ); +} - p2->m_texcoord[i] = float_mid( r2a->m_texcoord[i], r2b->m_texcoord[i] ); - } - } +inline const Vector3 &bitangent_for_index(const Array &vertices, std::size_t index) +{ + return reinterpret_cast( vertices[index].bitangent ); } -void Patch::RemovePoints( EMatrixMajor mt, bool bFirst ){ - std::size_t width, height, row_stride, col_stride; - - switch ( mt ) - { - case ROW: - col_stride = 1; - row_stride = m_width; - width = m_width; - height = m_height; - break; - case COL: - col_stride = m_width; - row_stride = 1; - width = m_height; - height = m_width; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } +#include "math/curve.h" - std::size_t pos = 0; - { - PatchControl* p1 = m_ctrl.data(); - for ( std::size_t w = 0; w != width; ++w, p1 += col_stride ) - { - { - PatchControl* p2 = p1; - for ( std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride ) - { - if ( 0 ) { //p2->m_selectable.isSelected()) - pos = h; - break; - } - } - if ( pos != 0 ) { - break; - } - } +inline PatchControl QuadraticBezier_evaluate(const PatchControl *firstPoint, double t) +{ + PatchControl result = {Vector3(0, 0, 0), Vector2(0, 0)}; + double denominator = 0; + + { + double weight = BernsteinPolynomial::apply(t); + vector3_add(result.m_vertex, vector3_scaled(firstPoint[0].m_vertex, weight)); + vector2_add(result.m_texcoord, vector2_scaled(firstPoint[0].m_texcoord, weight)); + denominator += weight; + } + { + double weight = BernsteinPolynomial::apply(t); + vector3_add(result.m_vertex, vector3_scaled(firstPoint[1].m_vertex, weight)); + vector2_add(result.m_texcoord, vector2_scaled(firstPoint[1].m_texcoord, weight)); + denominator += weight; + } + { + double weight = BernsteinPolynomial::apply(t); + vector3_add(result.m_vertex, vector3_scaled(firstPoint[2].m_vertex, weight)); + vector2_add(result.m_texcoord, vector2_scaled(firstPoint[2].m_texcoord, weight)); + denominator += weight; + } + + vector3_divide(result.m_vertex, denominator); + vector2_divide(result.m_texcoord, denominator); + return result; +} + +inline Vector3 vector3_linear_interpolated(const Vector3 &a, const Vector3 &b, double t) +{ + return vector3_added(vector3_scaled(a, 1.0 - t), vector3_scaled(b, t)); +} - { - PatchControl* p2 = p1; - for ( std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride ) - { - if ( 0 ) { //p2->m_selectable.isSelected()) - pos = h; - break; - } - } - if ( pos != 0 ) { - break; - } - } - } - } +inline Vector2 vector2_linear_interpolated(const Vector2 &a, const Vector2 &b, double t) +{ + return vector2_added(vector2_scaled(a, 1.0 - t), vector2_scaled(b, t)); +} - Array tmp( m_ctrl ); - - std::size_t row_stride2, col_stride2; - switch ( mt ) - { - case ROW: - setDims( m_width, m_height - 2 ); - col_stride2 = 1; - row_stride2 = m_width; - break; - case COL: - setDims( m_width - 2, m_height ); - col_stride2 = m_width; - row_stride2 = 1; - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } - if ( bFirst ) { - pos = height - 3; - } - else - { - pos = 2; - } - if ( pos >= height ) { - if ( bFirst ) { - pos = height - 3; - } - else - { - pos = 2; - } - } - else if ( pos == 0 ) { - pos = 2; - } - else if ( pos > height - 3 ) { - pos = height - 3; - } - else if ( pos % 2 ) { - ++pos; - } +void normalise_safe(Vector3 &normal) +{ + if (!vector3_equal(normal, g_vector3_identity)) { + vector3_normalise(normal); + } +} - for ( std::size_t w = 0; w != width; w++ ) - { - PatchControl* p1 = tmp.data() + ( w * col_stride ); - PatchControl* p2 = m_ctrl.data() + ( w * col_stride2 ); - for ( std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride ) - { - if ( h == pos ) { - p1 += 2 * row_stride2; h += 2; - } - *p2 = *p1; - } +inline void QuadraticBezier_evaluate(const PatchControl &a, const PatchControl &b, const PatchControl &c, double t, + PatchControl &point, PatchControl &left, PatchControl &right) +{ + left.m_vertex = vector3_linear_interpolated(a.m_vertex, b.m_vertex, t); + left.m_texcoord = vector2_linear_interpolated(a.m_texcoord, b.m_texcoord, t); + right.m_vertex = vector3_linear_interpolated(b.m_vertex, c.m_vertex, t); + right.m_texcoord = vector2_linear_interpolated(b.m_texcoord, c.m_texcoord, t); + point.m_vertex = vector3_linear_interpolated(left.m_vertex, right.m_vertex, t); + point.m_texcoord = vector2_linear_interpolated(left.m_texcoord, right.m_texcoord, t); +} - p1 = tmp.data() + ( w * col_stride + pos * row_stride ); - p2 = m_ctrl.data() + ( w * col_stride2 + pos * row_stride2 ); +void Patch::TesselateSubMatrixFixed(ArbitraryMeshVertex *vertices, std::size_t strideX, std::size_t strideY, + unsigned int nFlagsX, unsigned int nFlagsY, PatchControl *subMatrix[3][3]) +{ + double incrementU = 1.0 / m_subdivisions_x; + double incrementV = 1.0 / m_subdivisions_y; + const std::size_t width = m_subdivisions_x + 1; + const std::size_t height = m_subdivisions_y + 1; + + for (std::size_t i = 0; i != width; ++i) { + double tU = (i + 1 == width) ? 1 : i * incrementU; + PatchControl pointX[3]; + PatchControl leftX[3]; + PatchControl rightX[3]; + QuadraticBezier_evaluate(*subMatrix[0][0], *subMatrix[0][1], *subMatrix[0][2], tU, pointX[0], leftX[0], + rightX[0]); + QuadraticBezier_evaluate(*subMatrix[1][0], *subMatrix[1][1], *subMatrix[1][2], tU, pointX[1], leftX[1], + rightX[1]); + QuadraticBezier_evaluate(*subMatrix[2][0], *subMatrix[2][1], *subMatrix[2][2], tU, pointX[2], leftX[2], + rightX[2]); + + ArbitraryMeshVertex *p = vertices + i * strideX; + for (std::size_t j = 0; j != height; ++j) { + if ((j == 0 || j + 1 == height) && (i == 0 || i + 1 == width)) { + } else { + double tV = (j + 1 == height) ? 1 : j * incrementV; + + PatchControl pointY[3]; + PatchControl leftY[3]; + PatchControl rightY[3]; + QuadraticBezier_evaluate(*subMatrix[0][0], *subMatrix[1][0], *subMatrix[2][0], tV, pointY[0], leftY[0], + rightY[0]); + QuadraticBezier_evaluate(*subMatrix[0][1], *subMatrix[1][1], *subMatrix[2][1], tV, pointY[1], leftY[1], + rightY[1]); + QuadraticBezier_evaluate(*subMatrix[0][2], *subMatrix[1][2], *subMatrix[2][2], tV, pointY[2], leftY[2], + rightY[2]); + + PatchControl point; + PatchControl left; + PatchControl right; + QuadraticBezier_evaluate(pointX[0], pointX[1], pointX[2], tV, point, left, right); + PatchControl up; + PatchControl down; + QuadraticBezier_evaluate(pointY[0], pointY[1], pointY[2], tU, point, up, down); + + vertex3f_to_vector3(p->vertex) = point.m_vertex; + texcoord2f_to_vector2(p->texcoord) = point.m_texcoord; + + ArbitraryMeshVertex a, b, c; + + a.vertex = vertex3f_for_vector3(left.m_vertex); + a.texcoord = texcoord2f_for_vector2(left.m_texcoord); + b.vertex = vertex3f_for_vector3(right.m_vertex); + b.texcoord = texcoord2f_for_vector2(right.m_texcoord); + + if (i != 0) { + c.vertex = vertex3f_for_vector3(up.m_vertex); + c.texcoord = texcoord2f_for_vector2(up.m_texcoord); + } else { + c.vertex = vertex3f_for_vector3(down.m_vertex); + c.texcoord = texcoord2f_for_vector2(down.m_texcoord); + } + + Vector3 normal = vector3_normalised( + vector3_cross(right.m_vertex - left.m_vertex, up.m_vertex - down.m_vertex)); + + Vector3 tangent, bitangent; + ArbitraryMeshTriangle_calcTangents(a, b, c, tangent, bitangent); + vector3_normalise(tangent); + vector3_normalise(bitangent); + + if (((nFlagsX & AVERAGE) != 0 && i == 0) || ((nFlagsY & AVERAGE) != 0 && j == 0)) { + normal3f_to_vector3(p->normal) = vector3_normalised( + vector3_added(normal3f_to_vector3(p->normal), normal)); + normal3f_to_vector3(p->tangent) = vector3_normalised( + vector3_added(normal3f_to_vector3(p->tangent), tangent)); + normal3f_to_vector3(p->bitangent) = vector3_normalised( + vector3_added(normal3f_to_vector3(p->bitangent), bitangent)); + } else { + normal3f_to_vector3(p->normal) = normal; + normal3f_to_vector3(p->tangent) = tangent; + normal3f_to_vector3(p->bitangent) = bitangent; + } + } + + p += strideY; + } + } +} + +void Patch::TesselateSubMatrix(const BezierCurveTree *BX, const BezierCurveTree *BY, + std::size_t offStartX, std::size_t offStartY, + std::size_t offEndX, std::size_t offEndY, + std::size_t nFlagsX, std::size_t nFlagsY, + Vector3 &left, Vector3 &mid, Vector3 &right, + Vector2 &texLeft, Vector2 &texMid, Vector2 &texRight, + bool bTranspose) +{ + int newFlagsX, newFlagsY; - for ( std::size_t i = 0; i < 3; i++ ) - { - ( p2 - row_stride2 )->m_vertex[i] = ( ( p1 + 2 * row_stride )->m_vertex[i] + ( p1 - 2 * row_stride )->m_vertex[i] ) * 0.5f; + Vector3 tmp; + Vector3 vertex_0_0, vertex_0_1, vertex_1_0, vertex_1_1, vertex_2_0, vertex_2_1; + Vector2 texTmp; + Vector2 texcoord_0_0, texcoord_0_1, texcoord_1_0, texcoord_1_1, texcoord_2_0, texcoord_2_1; - ( p2 - row_stride2 )->m_vertex[i] = ( p2 - row_stride2 )->m_vertex[i] + ( 2.0f * ( ( p1 )->m_vertex[i] - ( p2 - row_stride2 )->m_vertex[i] ) ); - } - for ( std::size_t i = 0; i < 2; i++ ) - { - ( p2 - row_stride2 )->m_texcoord[i] = ( ( p1 + 2 * row_stride )->m_texcoord[i] + ( p1 - 2 * row_stride )->m_texcoord[i] ) * 0.5f; - - ( p2 - row_stride2 )->m_texcoord[i] = ( p2 - row_stride2 )->m_texcoord[i] + ( 2.0f * ( ( p1 )->m_texcoord[i] - ( p2 - row_stride2 )->m_texcoord[i] ) ); - } - } -} - -void Patch::ConstructSeam( EPatchCap eType, Vector3* p, std::size_t width ){ - switch ( eType ) - { - case eCapIBevel: - { - setDims( 3, 3 ); - m_ctrl[0].m_vertex = p[0]; - m_ctrl[1].m_vertex = p[1]; - m_ctrl[2].m_vertex = p[1]; - m_ctrl[3].m_vertex = p[1]; - m_ctrl[4].m_vertex = p[1]; - m_ctrl[5].m_vertex = p[1]; - m_ctrl[6].m_vertex = p[2]; - m_ctrl[7].m_vertex = p[1]; - m_ctrl[8].m_vertex = p[1]; - } - break; - case eCapBevel: - { - setDims( 3, 3 ); - Vector3 p3( vector3_added( p[2], vector3_subtracted( p[0], p[1] ) ) ); - m_ctrl[0].m_vertex = p3; - m_ctrl[1].m_vertex = p3; - m_ctrl[2].m_vertex = p[2]; - m_ctrl[3].m_vertex = p3; - m_ctrl[4].m_vertex = p3; - m_ctrl[5].m_vertex = p[1]; - m_ctrl[6].m_vertex = p3; - m_ctrl[7].m_vertex = p3; - m_ctrl[8].m_vertex = p[0]; - } - break; - case eCapEndCap: - { - Vector3 p5( vector3_mid( p[0], p[4] ) ); - - setDims( 3, 3 ); - m_ctrl[0].m_vertex = p[0]; - m_ctrl[1].m_vertex = p5; - m_ctrl[2].m_vertex = p[4]; - m_ctrl[3].m_vertex = p[1]; - m_ctrl[4].m_vertex = p[2]; - m_ctrl[5].m_vertex = p[3]; - m_ctrl[6].m_vertex = p[2]; - m_ctrl[7].m_vertex = p[2]; - m_ctrl[8].m_vertex = p[2]; - } - break; - case eCapIEndCap: - { - setDims( 5, 3 ); - m_ctrl[0].m_vertex = p[4]; - m_ctrl[1].m_vertex = p[3]; - m_ctrl[2].m_vertex = p[2]; - m_ctrl[3].m_vertex = p[1]; - m_ctrl[4].m_vertex = p[0]; - m_ctrl[5].m_vertex = p[3]; - m_ctrl[6].m_vertex = p[3]; - m_ctrl[7].m_vertex = p[2]; - m_ctrl[8].m_vertex = p[1]; - m_ctrl[9].m_vertex = p[1]; - m_ctrl[10].m_vertex = p[3]; - m_ctrl[11].m_vertex = p[3]; - m_ctrl[12].m_vertex = p[2]; - m_ctrl[13].m_vertex = p[1]; - m_ctrl[14].m_vertex = p[1]; - } - break; - case eCapCylinder: - { - std::size_t mid = ( width - 1 ) >> 1; - - bool degenerate = ( mid % 2 ) != 0; - - std::size_t newHeight = mid + ( degenerate ? 2 : 1 ); - - setDims( 3, newHeight ); - - if ( degenerate ) { - ++mid; - for ( std::size_t i = width; i != width + 2; ++i ) - { - p[i] = p[width - 1]; - } - } - - { - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t i = 0; i != m_height; ++i, pCtrl += m_width ) - { - pCtrl->m_vertex = p[i]; - } - } - { - PatchControl* pCtrl = m_ctrl.data() + 2; - std::size_t h = m_height - 1; - for ( std::size_t i = 0; i != m_height; ++i, pCtrl += m_width ) - { - pCtrl->m_vertex = p[h + ( h - i )]; - } - } - - Redisperse( COL ); - } - break; - default: - ERROR_MESSAGE( "invalid patch-cap type" ); - return; - } - CapTexture(); - controlPointsChanged(); -} - -void Patch::ProjectTexture( int nAxis ){ - undoSave(); - - int s, t; - - switch ( nAxis ) - { - case 2: - s = 0; - t = 1; - break; - case 0: - s = 1; - t = 2; - break; - case 1: - s = 0; - t = 2; - break; - default: - ERROR_MESSAGE( "invalid axis" ); - return; - } - - float fWidth = 1 / ( m_state->getTexture().width * Texdef_getDefaultTextureScale() ); - float fHeight = 1 / ( m_state->getTexture().height * -Texdef_getDefaultTextureScale() ); - - for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i ) - { - ( *i ).m_texcoord[0] = ( *i ).m_vertex[s] * fWidth; - ( *i ).m_texcoord[1] = ( *i ).m_vertex[t] * fHeight; - } - - controlPointsChanged(); -} - -void Patch::constructPlane( const AABB& aabb, int axis, std::size_t width, std::size_t height ){ - setDims( width, height ); - - int x, y, z; - switch ( axis ) - { - case 2: x = 0; y = 1; z = 2; break; - case 1: x = 0; y = 2; z = 1; break; - case 0: x = 1; y = 2; z = 0; break; - default: - ERROR_MESSAGE( "invalid view-type" ); - return; - } - - if ( m_width < MIN_PATCH_WIDTH || m_width > MAX_PATCH_WIDTH ) { - m_width = 3; - } - if ( m_height < MIN_PATCH_HEIGHT || m_height > MAX_PATCH_HEIGHT ) { - m_height = 3; - } - - Vector3 vStart; - vStart[x] = aabb.origin[x] - aabb.extents[x]; - vStart[y] = aabb.origin[y] - aabb.extents[y]; - vStart[z] = aabb.origin[z]; - - float xAdj = fabsf( ( vStart[x] - ( aabb.origin[x] + aabb.extents[x] ) ) / (float)( m_width - 1 ) ); - float yAdj = fabsf( ( vStart[y] - ( aabb.origin[y] + aabb.extents[y] ) ) / (float)( m_height - 1 ) ); - - Vector3 vTmp; - vTmp[z] = vStart[z]; - PatchControl* pCtrl = m_ctrl.data(); - - vTmp[y] = vStart[y]; - for ( std::size_t h = 0; h < m_height; h++ ) - { - vTmp[x] = vStart[x]; - for ( std::size_t w = 0; w < m_width; w++, ++pCtrl ) - { - pCtrl->m_vertex = vTmp; - vTmp[x] += xAdj; - } - vTmp[y] += yAdj; - } - - NaturalTexture(); -} - -void Patch::ConstructPrefab( const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width, std::size_t height ){ - Vector3 vPos[3]; - - if ( eType != ePlane ) { - vPos[0] = vector3_subtracted( aabb.origin, aabb.extents ); - vPos[1] = aabb.origin; - vPos[2] = vector3_added( aabb.origin, aabb.extents ); - } - - if ( eType == ePlane ) { - constructPlane( aabb, axis, width, height ); - } - else if ( eType == eSqCylinder - || eType == eCylinder - || eType == eDenseCylinder - || eType == eVeryDenseCylinder - || eType == eCone - || eType == eSphere ) { - unsigned char *pIndex; - unsigned char pCylIndex[] = - { - 0, 0, - 1, 0, - 2, 0, - 2, 1, - 2, 2, - 1, 2, - 0, 2, - 0, 1, - 0, 0 - }; - - - PatchControl *pStart; - switch ( eType ) - { - case eSqCylinder: setDims( 9, 3 ); - pStart = m_ctrl.data(); - break; - case eDenseCylinder: - case eVeryDenseCylinder: - case eCylinder: - setDims( 9, 3 ); - pStart = m_ctrl.data() + 1; - break; - case eCone: setDims( 9, 3 ); - pStart = m_ctrl.data() + 1; - break; - case eSphere: - setDims( 9, 5 ); - pStart = m_ctrl.data() + ( 9 + 1 ); - break; - default: - ERROR_MESSAGE( "this should be unreachable" ); - return; - } - - for ( std::size_t h = 0; h < 3; h++, pStart += 9 ) - { - pIndex = pCylIndex; - PatchControl* pCtrl = pStart; - for ( std::size_t w = 0; w < 8; w++, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; - pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; - pCtrl->m_vertex[2] = vPos[h][2]; - pIndex += 2; - } - } - - switch ( eType ) - { - case eSqCylinder: - { - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 ) - { - pCtrl[8].m_vertex = pCtrl[0].m_vertex; - } - } - break; - case eDenseCylinder: - case eVeryDenseCylinder: - case eCylinder: - { - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 ) - { - pCtrl[0].m_vertex = pCtrl[8].m_vertex; - } - } - break; - case eCone: - { - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t h = 0; h < 2; h++, pCtrl += 9 ) - { - pCtrl[0].m_vertex = pCtrl[8].m_vertex; - } - } - { - PatchControl* pCtrl = m_ctrl.data() + 9 * 2; - for ( std::size_t w = 0; w < 9; w++, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[1][0]; - pCtrl->m_vertex[1] = vPos[1][1]; - pCtrl->m_vertex[2] = vPos[2][2]; - } - } - break; - case eSphere: - { - PatchControl* pCtrl = m_ctrl.data() + 9; - for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 ) - { - pCtrl[0].m_vertex = pCtrl[8].m_vertex; - } - } - { - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t w = 0; w < 9; w++, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[1][0]; - pCtrl->m_vertex[1] = vPos[1][1]; - pCtrl->m_vertex[2] = vPos[0][2]; - } - } - { - PatchControl* pCtrl = m_ctrl.data() + ( 9 * 4 ); - for ( std::size_t w = 0; w < 9; w++, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[1][0]; - pCtrl->m_vertex[1] = vPos[1][1]; - pCtrl->m_vertex[2] = vPos[2][2]; - } - } - break; - default: - ERROR_MESSAGE( "this should be unreachable" ); - return; - } - } - else if ( eType == eXactCylinder ) { - int n = ( width - 1 ) / 2; // n = number of segments - setDims( width, height ); - - // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); - // vPos[1] = aabb.origin; - // vPos[2] = vector3_added(aabb.origin, aabb.extents); - - int i, j; - float f = 1 / cos( M_PI / n ); - for ( i = 0; i < width; ++i ) - { - float angle = ( M_PI * i ) / n; // 0 to 2pi - float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f ); - float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f ); - for ( j = 0; j < height; ++j ) - { - float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) ); - PatchControl *v; - v = &m_ctrl.data()[j * width + i]; - v->m_vertex[0] = x; - v->m_vertex[1] = y; - v->m_vertex[2] = z; - } - } - } - else if ( eType == eXactCone ) { - int n = ( width - 1 ) / 2; // n = number of segments - setDims( width, height ); - - // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); - // vPos[1] = aabb.origin; - // vPos[2] = vector3_added(aabb.origin, aabb.extents); - - int i, j; - float f = 1 / cos( M_PI / n ); - for ( i = 0; i < width; ++i ) - { - float angle = ( M_PI * i ) / n; - for ( j = 0; j < height; ++j ) - { - float x = vPos[1][0] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f ); - float y = vPos[1][1] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f ); - float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) ); - PatchControl *v; - v = &m_ctrl.data()[j * width + i]; - v->m_vertex[0] = x; - v->m_vertex[1] = y; - v->m_vertex[2] = z; - } - } - } - else if ( eType == eXactSphere ) { - int n = ( width - 1 ) / 2; // n = number of segments (yaw) - int m = ( height - 1 ) / 2; // m = number of segments (pitch) - setDims( width, height ); - - // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); - // vPos[1] = aabb.origin; - // vPos[2] = vector3_added(aabb.origin, aabb.extents); - - int i, j; - float f = 1 / cos( M_PI / n ); - float g = 1 / cos( M_PI / ( 2 * m ) ); - for ( i = 0; i < width; ++i ) - { - float angle = ( M_PI * i ) / n; - for ( j = 0; j < height; ++j ) - { - float angle2 = ( M_PI * j ) / ( 2 * m ); - float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f ); - float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f ); - float z = vPos[1][2] + ( vPos[2][2] - vPos[1][2] ) * -cos( angle2 ) * ( ( j & 1 ) ? g : 1.0f ); - PatchControl *v; - v = &m_ctrl.data()[j * width + i]; - v->m_vertex[0] = x; - v->m_vertex[1] = y; - v->m_vertex[2] = z; - } - } - } - else if ( eType == eBevel ) { - unsigned char *pIndex; - unsigned char pBevIndex[] = - { - 0, 0, - 2, 0, - 2, 2, - }; - - setDims( 3, 3 ); - - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t h = 0; h < 3; h++ ) - { - pIndex = pBevIndex; - for ( std::size_t w = 0; w < 3; w++, pIndex += 2, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; - pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; - pCtrl->m_vertex[2] = vPos[h][2]; - } - } - } - else if ( eType == eEndCap ) { - unsigned char *pIndex; - unsigned char pEndIndex[] = - { - 2, 0, - 2, 2, - 1, 2, - 0, 2, - 0, 0, - }; - - setDims( 5, 3 ); - - PatchControl* pCtrl = m_ctrl.data(); - for ( std::size_t h = 0; h < 3; h++ ) - { - pIndex = pEndIndex; - for ( std::size_t w = 0; w < 5; w++, pIndex += 2, pCtrl++ ) - { - pCtrl->m_vertex[0] = vPos[pIndex[0]][0]; - pCtrl->m_vertex[1] = vPos[pIndex[1]][1]; - pCtrl->m_vertex[2] = vPos[h][2]; - } - } - } - - if ( eType == eDenseCylinder ) { - InsertRemove( true, false, true ); - } - - if ( eType == eVeryDenseCylinder ) { - InsertRemove( true, false, false ); - InsertRemove( true, false, true ); - } - - NaturalTexture(); -} - -void Patch::RenderDebug( RenderStateFlags state ) const { - for ( std::size_t i = 0; i < m_tess.m_numStrips; i++ ) - { - glBegin( GL_QUAD_STRIP ); - for ( std::size_t j = 0; j < m_tess.m_lenStrips; j++ ) - { - glNormal3fv( normal3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->normal ) ); - glTexCoord2fv( texcoord2f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->texcoord ) ); - glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->vertex ) ); - } - glEnd(); - } -} - -void RenderablePatchSolid::RenderNormals() const { - const std::size_t width = m_tess.m_numStrips + 1; - const std::size_t height = m_tess.m_lenStrips >> 1; - glBegin( GL_LINES ); - for ( std::size_t i = 0; i < width; i++ ) - { - for ( std::size_t j = 0; j < height; j++ ) - { - { - Vector3 vNormal( - vector3_added( - vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ), - vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->normal ), 8 ) - ) - ); - glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) ); - glVertex3fv( &vNormal[0] ); - } - { - Vector3 vNormal( - vector3_added( - vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ), - vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->tangent ), 8 ) - ) - ); - glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) ); - glVertex3fv( &vNormal[0] ); - } - { - Vector3 vNormal( - vector3_added( - vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ), - vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->bitangent ), 8 ) - ) - ); - glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) ); - glVertex3fv( &vNormal[0] ); - } - } - } - glEnd(); -} - -#define DEGEN_0a 0x01 -#define DEGEN_1a 0x02 -#define DEGEN_2a 0x04 -#define DEGEN_0b 0x08 -#define DEGEN_1b 0x10 -#define DEGEN_2b 0x20 -#define SPLIT 0x40 -#define AVERAGE 0x80 - - -unsigned int subarray_get_degen( PatchControlIter subarray, std::size_t strideU, std::size_t strideV ){ - unsigned int nDegen = 0; - const PatchControl* p1; - const PatchControl* p2; - - p1 = subarray; - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_0a; - } - p1 = p2; - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_0b; - } - - p1 = subarray + strideV; - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_1a; - } - p1 = p2; - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_1b; - } - - p1 = subarray + ( strideV << 1 ); - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_2a; - } - p1 = p2; - p2 = p1 + strideU; - if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) { - nDegen |= DEGEN_2b; - } - - return nDegen; -} - - -inline void deCasteljau3( const Vector3& P0, const Vector3& P1, const Vector3& P2, Vector3& P01, Vector3& P12, Vector3& P012 ){ - P01 = vector3_mid( P0, P1 ); - P12 = vector3_mid( P1, P2 ); - P012 = vector3_mid( P01, P12 ); -} - -inline void BezierInterpolate3( const Vector3& start, Vector3& left, Vector3& mid, Vector3& right, const Vector3& end ){ - left = vector3_mid( start, mid ); - right = vector3_mid( mid, end ); - mid = vector3_mid( left, right ); -} - -inline void BezierInterpolate2( const Vector2& start, Vector2& left, Vector2& mid, Vector2& right, const Vector2& end ){ - left[0] = float_mid( start[0], mid[0] ); - left[1] = float_mid( start[1], mid[1] ); - right[0] = float_mid( mid[0], end[0] ); - right[1] = float_mid( mid[1], end[1] ); - mid[0] = float_mid( left[0], right[0] ); - mid[1] = float_mid( left[1], right[1] ); -} - - -inline Vector2& texcoord_for_index( Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].texcoord ); -} - -inline Vector3& vertex_for_index( Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].vertex ); -} - -inline Vector3& normal_for_index( Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].normal ); -} - -inline Vector3& tangent_for_index( Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].tangent ); -} - -inline Vector3& bitangent_for_index( Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].bitangent ); -} - -inline const Vector2& texcoord_for_index( const Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].texcoord ); -} - -inline const Vector3& vertex_for_index( const Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].vertex ); -} - -inline const Vector3& normal_for_index( const Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].normal ); -} - -inline const Vector3& tangent_for_index( const Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].tangent ); -} - -inline const Vector3& bitangent_for_index( const Array& vertices, std::size_t index ){ - return reinterpret_cast( vertices[index].bitangent ); -} - -#include "math/curve.h" - -inline PatchControl QuadraticBezier_evaluate( const PatchControl* firstPoint, double t ){ - PatchControl result = { Vector3( 0, 0, 0 ), Vector2( 0, 0 ) }; - double denominator = 0; - - { - double weight = BernsteinPolynomial::apply( t ); - vector3_add( result.m_vertex, vector3_scaled( firstPoint[0].m_vertex, weight ) ); - vector2_add( result.m_texcoord, vector2_scaled( firstPoint[0].m_texcoord, weight ) ); - denominator += weight; - } - { - double weight = BernsteinPolynomial::apply( t ); - vector3_add( result.m_vertex, vector3_scaled( firstPoint[1].m_vertex, weight ) ); - vector2_add( result.m_texcoord, vector2_scaled( firstPoint[1].m_texcoord, weight ) ); - denominator += weight; - } - { - double weight = BernsteinPolynomial::apply( t ); - vector3_add( result.m_vertex, vector3_scaled( firstPoint[2].m_vertex, weight ) ); - vector2_add( result.m_texcoord, vector2_scaled( firstPoint[2].m_texcoord, weight ) ); - denominator += weight; - } - - vector3_divide( result.m_vertex, denominator ); - vector2_divide( result.m_texcoord, denominator ); - return result; -} - -inline Vector3 vector3_linear_interpolated( const Vector3& a, const Vector3& b, double t ){ - return vector3_added( vector3_scaled( a, 1.0 - t ), vector3_scaled( b, t ) ); -} - -inline Vector2 vector2_linear_interpolated( const Vector2& a, const Vector2& b, double t ){ - return vector2_added( vector2_scaled( a, 1.0 - t ), vector2_scaled( b, t ) ); -} - -void normalise_safe( Vector3& normal ){ - if ( !vector3_equal( normal, g_vector3_identity ) ) { - vector3_normalise( normal ); - } -} - -inline void QuadraticBezier_evaluate( const PatchControl& a, const PatchControl& b, const PatchControl& c, double t, PatchControl& point, PatchControl& left, PatchControl& right ){ - left.m_vertex = vector3_linear_interpolated( a.m_vertex, b.m_vertex, t ); - left.m_texcoord = vector2_linear_interpolated( a.m_texcoord, b.m_texcoord, t ); - right.m_vertex = vector3_linear_interpolated( b.m_vertex, c.m_vertex, t ); - right.m_texcoord = vector2_linear_interpolated( b.m_texcoord, c.m_texcoord, t ); - point.m_vertex = vector3_linear_interpolated( left.m_vertex, right.m_vertex, t ); - point.m_texcoord = vector2_linear_interpolated( left.m_texcoord, right.m_texcoord, t ); -} - -void Patch::TesselateSubMatrixFixed( ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3] ){ - double incrementU = 1.0 / m_subdivisions_x; - double incrementV = 1.0 / m_subdivisions_y; - const std::size_t width = m_subdivisions_x + 1; - const std::size_t height = m_subdivisions_y + 1; - - for ( std::size_t i = 0; i != width; ++i ) - { - double tU = ( i + 1 == width ) ? 1 : i * incrementU; - PatchControl pointX[3]; - PatchControl leftX[3]; - PatchControl rightX[3]; - QuadraticBezier_evaluate( *subMatrix[0][0], *subMatrix[0][1], *subMatrix[0][2], tU, pointX[0], leftX[0], rightX[0] ); - QuadraticBezier_evaluate( *subMatrix[1][0], *subMatrix[1][1], *subMatrix[1][2], tU, pointX[1], leftX[1], rightX[1] ); - QuadraticBezier_evaluate( *subMatrix[2][0], *subMatrix[2][1], *subMatrix[2][2], tU, pointX[2], leftX[2], rightX[2] ); - - ArbitraryMeshVertex* p = vertices + i * strideX; - for ( std::size_t j = 0; j != height; ++j ) - { - if ( ( j == 0 || j + 1 == height ) && ( i == 0 || i + 1 == width ) ) { - } - else - { - double tV = ( j + 1 == height ) ? 1 : j * incrementV; - - PatchControl pointY[3]; - PatchControl leftY[3]; - PatchControl rightY[3]; - QuadraticBezier_evaluate( *subMatrix[0][0], *subMatrix[1][0], *subMatrix[2][0], tV, pointY[0], leftY[0], rightY[0] ); - QuadraticBezier_evaluate( *subMatrix[0][1], *subMatrix[1][1], *subMatrix[2][1], tV, pointY[1], leftY[1], rightY[1] ); - QuadraticBezier_evaluate( *subMatrix[0][2], *subMatrix[1][2], *subMatrix[2][2], tV, pointY[2], leftY[2], rightY[2] ); - - PatchControl point; - PatchControl left; - PatchControl right; - QuadraticBezier_evaluate( pointX[0], pointX[1], pointX[2], tV, point, left, right ); - PatchControl up; - PatchControl down; - QuadraticBezier_evaluate( pointY[0], pointY[1], pointY[2], tU, point, up, down ); - - vertex3f_to_vector3( p->vertex ) = point.m_vertex; - texcoord2f_to_vector2( p->texcoord ) = point.m_texcoord; - - ArbitraryMeshVertex a, b, c; - - a.vertex = vertex3f_for_vector3( left.m_vertex ); - a.texcoord = texcoord2f_for_vector2( left.m_texcoord ); - b.vertex = vertex3f_for_vector3( right.m_vertex ); - b.texcoord = texcoord2f_for_vector2( right.m_texcoord ); - - if ( i != 0 ) { - c.vertex = vertex3f_for_vector3( up.m_vertex ); - c.texcoord = texcoord2f_for_vector2( up.m_texcoord ); - } - else - { - c.vertex = vertex3f_for_vector3( down.m_vertex ); - c.texcoord = texcoord2f_for_vector2( down.m_texcoord ); - } - - Vector3 normal = vector3_normalised( vector3_cross( right.m_vertex - left.m_vertex, up.m_vertex - down.m_vertex ) ); - - Vector3 tangent, bitangent; - ArbitraryMeshTriangle_calcTangents( a, b, c, tangent, bitangent ); - vector3_normalise( tangent ); - vector3_normalise( bitangent ); - - if ( ( ( nFlagsX & AVERAGE ) != 0 && i == 0 ) || ( ( nFlagsY & AVERAGE ) != 0 && j == 0 ) ) { - normal3f_to_vector3( p->normal ) = vector3_normalised( vector3_added( normal3f_to_vector3( p->normal ), normal ) ); - normal3f_to_vector3( p->tangent ) = vector3_normalised( vector3_added( normal3f_to_vector3( p->tangent ), tangent ) ); - normal3f_to_vector3( p->bitangent ) = vector3_normalised( vector3_added( normal3f_to_vector3( p->bitangent ), bitangent ) ); - } - else - { - normal3f_to_vector3( p->normal ) = normal; - normal3f_to_vector3( p->tangent ) = tangent; - normal3f_to_vector3( p->bitangent ) = bitangent; - } - } - - p += strideY; - } - } -} - -void Patch::TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY, - std::size_t offStartX, std::size_t offStartY, - std::size_t offEndX, std::size_t offEndY, - std::size_t nFlagsX, std::size_t nFlagsY, - Vector3& left, Vector3& mid, Vector3& right, - Vector2& texLeft, Vector2& texMid, Vector2& texRight, - bool bTranspose ){ - int newFlagsX, newFlagsY; - - Vector3 tmp; - Vector3 vertex_0_0, vertex_0_1, vertex_1_0, vertex_1_1, vertex_2_0, vertex_2_1; - Vector2 texTmp; - Vector2 texcoord_0_0, texcoord_0_1, texcoord_1_0, texcoord_1_1, texcoord_2_0, texcoord_2_1; - - { - // texcoords - - BezierInterpolate2( texcoord_for_index( m_tess.m_vertices, offStartX + offStartY ), - texcoord_0_0, - texcoord_for_index( m_tess.m_vertices, BX->index + offStartY ), - texcoord_0_1, - texcoord_for_index( m_tess.m_vertices, offEndX + offStartY ) ); - - - BezierInterpolate2( texcoord_for_index( m_tess.m_vertices, offStartX + offEndY ), - texcoord_2_0, - texcoord_for_index( m_tess.m_vertices, BX->index + offEndY ), - texcoord_2_1, - texcoord_for_index( m_tess.m_vertices, offEndX + offEndY ) ); - - texTmp = texMid; - - BezierInterpolate2( texLeft, - texcoord_1_0, - texTmp, - texcoord_1_1, - texRight ); - - if ( !BezierCurveTree_isLeaf( BY ) ) { - texcoord_for_index( m_tess.m_vertices, BX->index + BY->index ) = texTmp; - } - - - if ( !BezierCurveTree_isLeaf( BX->left ) ) { - texcoord_for_index( m_tess.m_vertices, BX->left->index + offStartY ) = texcoord_0_0; - texcoord_for_index( m_tess.m_vertices, BX->left->index + offEndY ) = texcoord_2_0; + { + // texcoords - if ( !BezierCurveTree_isLeaf( BY ) ) { - texcoord_for_index( m_tess.m_vertices, BX->left->index + BY->index ) = texcoord_1_0; - } - } - if ( !BezierCurveTree_isLeaf( BX->right ) ) { - texcoord_for_index( m_tess.m_vertices, BX->right->index + offStartY ) = texcoord_0_1; - texcoord_for_index( m_tess.m_vertices, BX->right->index + offEndY ) = texcoord_2_1; - - if ( !BezierCurveTree_isLeaf( BY ) ) { - texcoord_for_index( m_tess.m_vertices, BX->right->index + BY->index ) = texcoord_1_1; - } - } - - - // verts - - BezierInterpolate3( vertex_for_index( m_tess.m_vertices, offStartX + offStartY ), - vertex_0_0, - vertex_for_index( m_tess.m_vertices, BX->index + offStartY ), - vertex_0_1, - vertex_for_index( m_tess.m_vertices, offEndX + offStartY ) ); - - - BezierInterpolate3( vertex_for_index( m_tess.m_vertices, offStartX + offEndY ), - vertex_2_0, - vertex_for_index( m_tess.m_vertices, BX->index + offEndY ), - vertex_2_1, - vertex_for_index( m_tess.m_vertices, offEndX + offEndY ) ); - - - tmp = mid; - - BezierInterpolate3( left, - vertex_1_0, - tmp, - vertex_1_1, - right ); - - if ( !BezierCurveTree_isLeaf( BY ) ) { - vertex_for_index( m_tess.m_vertices, BX->index + BY->index ) = tmp; - } - - - if ( !BezierCurveTree_isLeaf( BX->left ) ) { - vertex_for_index( m_tess.m_vertices, BX->left->index + offStartY ) = vertex_0_0; - vertex_for_index( m_tess.m_vertices, BX->left->index + offEndY ) = vertex_2_0; - - if ( !BezierCurveTree_isLeaf( BY ) ) { - vertex_for_index( m_tess.m_vertices, BX->left->index + BY->index ) = vertex_1_0; - } - } - if ( !BezierCurveTree_isLeaf( BX->right ) ) { - vertex_for_index( m_tess.m_vertices, BX->right->index + offStartY ) = vertex_0_1; - vertex_for_index( m_tess.m_vertices, BX->right->index + offEndY ) = vertex_2_1; - - if ( !BezierCurveTree_isLeaf( BY ) ) { - vertex_for_index( m_tess.m_vertices, BX->right->index + BY->index ) = vertex_1_1; - } - } - - // normals - - if ( nFlagsX & SPLIT ) { - ArbitraryMeshVertex a, b, c; - Vector3 tangentU; - - if ( !( nFlagsX & DEGEN_0a ) || !( nFlagsX & DEGEN_0b ) ) { - tangentU = vector3_subtracted( vertex_0_1, vertex_0_0 ); - a.vertex = vertex3f_for_vector3( vertex_0_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_0_0 ); - c.vertex = vertex3f_for_vector3( vertex_0_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_0_1 ); - } - else if ( !( nFlagsX & DEGEN_1a ) || !( nFlagsX & DEGEN_1b ) ) { - tangentU = vector3_subtracted( vertex_1_1, vertex_1_0 ); - a.vertex = vertex3f_for_vector3( vertex_1_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_1_0 ); - c.vertex = vertex3f_for_vector3( vertex_1_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_1_1 ); - } - else - { - tangentU = vector3_subtracted( vertex_2_1, vertex_2_0 ); - a.vertex = vertex3f_for_vector3( vertex_2_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_2_0 ); - c.vertex = vertex3f_for_vector3( vertex_2_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_2_1 ); - } - - Vector3 tangentV; - - if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_1a ) && ( nFlagsY & DEGEN_2a ) ) { - tangentV = vector3_subtracted( vertex_for_index( m_tess.m_vertices, BX->index + offEndY ), tmp ); - b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offEndY].vertex; - b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offEndY].texcoord; - } - else - { - tangentV = vector3_subtracted( tmp, vertex_for_index( m_tess.m_vertices, BX->index + offStartY ) ); - b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offStartY].vertex; - b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offStartY].texcoord; - } - - - Vector3 normal, s, t; - ArbitraryMeshVertex& v = m_tess.m_vertices[offStartY + BX->index]; - Vector3& p = normal3f_to_vector3( v.normal ); - Vector3& ps = normal3f_to_vector3( v.tangent ); - Vector3& pt = normal3f_to_vector3( v.bitangent ); - - if ( bTranspose ) { - normal = vector3_cross( tangentV, tangentU ); - } - else - { - normal = vector3_cross( tangentU, tangentV ); - } - normalise_safe( normal ); - - ArbitraryMeshTriangle_calcTangents( a, b, c, s, t ); - normalise_safe( s ); - normalise_safe( t ); - - if ( nFlagsX & AVERAGE ) { - p = vector3_normalised( vector3_added( p, normal ) ); - ps = vector3_normalised( vector3_added( ps, s ) ); - pt = vector3_normalised( vector3_added( pt, t ) ); - } - else - { - p = normal; - ps = s; - pt = t; - } - } - - { - ArbitraryMeshVertex a, b, c; - Vector3 tangentU; - - if ( !( nFlagsX & DEGEN_2a ) || !( nFlagsX & DEGEN_2b ) ) { - tangentU = vector3_subtracted( vertex_2_1, vertex_2_0 ); - a.vertex = vertex3f_for_vector3( vertex_2_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_2_0 ); - c.vertex = vertex3f_for_vector3( vertex_2_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_2_1 ); - } - else if ( !( nFlagsX & DEGEN_1a ) || !( nFlagsX & DEGEN_1b ) ) { - tangentU = vector3_subtracted( vertex_1_1, vertex_1_0 ); - a.vertex = vertex3f_for_vector3( vertex_1_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_1_0 ); - c.vertex = vertex3f_for_vector3( vertex_1_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_1_1 ); - } - else - { - tangentU = vector3_subtracted( vertex_0_1, vertex_0_0 ); - a.vertex = vertex3f_for_vector3( vertex_0_0 ); - a.texcoord = texcoord2f_for_vector2( texcoord_0_0 ); - c.vertex = vertex3f_for_vector3( vertex_0_1 ); - c.texcoord = texcoord2f_for_vector2( texcoord_0_1 ); - } - - Vector3 tangentV; - - if ( ( nFlagsY & DEGEN_0b ) && ( nFlagsY & DEGEN_1b ) && ( nFlagsY & DEGEN_2b ) ) { - tangentV = vector3_subtracted( tmp, vertex_for_index( m_tess.m_vertices, BX->index + offStartY ) ); - b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offStartY].vertex; - b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offStartY].texcoord; - } - else - { - tangentV = vector3_subtracted( vertex_for_index( m_tess.m_vertices, BX->index + offEndY ), tmp ); - b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offEndY].vertex; - b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offEndY].texcoord; - } - - ArbitraryMeshVertex& v = m_tess.m_vertices[offEndY + BX->index]; - Vector3& p = normal3f_to_vector3( v.normal ); - Vector3& ps = normal3f_to_vector3( v.tangent ); - Vector3& pt = normal3f_to_vector3( v.bitangent ); - - if ( bTranspose ) { - p = vector3_cross( tangentV, tangentU ); - } - else - { - p = vector3_cross( tangentU, tangentV ); - } - normalise_safe( p ); - - ArbitraryMeshTriangle_calcTangents( a, b, c, ps, pt ); - normalise_safe( ps ); - normalise_safe( pt ); - } - } - - - newFlagsX = newFlagsY = 0; - - if ( ( nFlagsX & DEGEN_0a ) && ( nFlagsX & DEGEN_0b ) ) { - newFlagsX |= DEGEN_0a; - newFlagsX |= DEGEN_0b; - } - if ( ( nFlagsX & DEGEN_1a ) && ( nFlagsX & DEGEN_1b ) ) { - newFlagsX |= DEGEN_1a; - newFlagsX |= DEGEN_1b; - } - if ( ( nFlagsX & DEGEN_2a ) && ( nFlagsX & DEGEN_2b ) ) { - newFlagsX |= DEGEN_2a; - newFlagsX |= DEGEN_2b; - } - if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_1a ) && ( nFlagsY & DEGEN_2a ) ) { - newFlagsY |= DEGEN_0a; - newFlagsY |= DEGEN_1a; - newFlagsY |= DEGEN_2a; - } - if ( ( nFlagsY & DEGEN_0b ) && ( nFlagsY & DEGEN_1b ) && ( nFlagsY & DEGEN_2b ) ) { - newFlagsY |= DEGEN_0b; - newFlagsY |= DEGEN_1b; - newFlagsY |= DEGEN_2b; - } - - - //if((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_2a)) { newFlagsX |= DEGEN_0a; newFlagsX |= DEGEN_1a; newFlagsX |= DEGEN_2a; } - //if((nFlagsX & DEGEN_0b) && (nFlagsX & DEGEN_1b) && (nFlagsX & DEGEN_2b)) { newFlagsX |= DEGEN_0b; newFlagsX |= DEGEN_1b; newFlagsX |= DEGEN_2b; } - - newFlagsX |= ( nFlagsX & SPLIT ); - newFlagsX |= ( nFlagsX & AVERAGE ); - - if ( !BezierCurveTree_isLeaf( BY ) ) { - { - int nTemp = newFlagsY; - - if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_0b ) ) { - newFlagsY |= DEGEN_0a; - newFlagsY |= DEGEN_0b; - } - newFlagsY |= ( nFlagsY & SPLIT ); - newFlagsY |= ( nFlagsY & AVERAGE ); - - Vector3& p = vertex_for_index( m_tess.m_vertices, BX->index + BY->index ); - Vector3 vTemp( p ); - - Vector2& p2 = texcoord_for_index( m_tess.m_vertices, BX->index + BY->index ); - Vector2 stTemp( p2 ); - - TesselateSubMatrix( BY, BX->left, - offStartY, offStartX, - offEndY, BX->index, - newFlagsY, newFlagsX, - vertex_0_0, vertex_1_0, vertex_2_0, - texcoord_0_0, texcoord_1_0, texcoord_2_0, - !bTranspose ); - - newFlagsY = nTemp; - p = vTemp; - p2 = stTemp; - } - - if ( ( nFlagsY & DEGEN_2a ) && ( nFlagsY & DEGEN_2b ) ) { - newFlagsY |= DEGEN_2a; newFlagsY |= DEGEN_2b; - } - - TesselateSubMatrix( BY, BX->right, - offStartY, BX->index, - offEndY, offEndX, - newFlagsY, newFlagsX, - vertex_0_1, vertex_1_1, vertex_2_1, - texcoord_0_1, texcoord_1_1, texcoord_2_1, - !bTranspose ); - } - else - { - if ( !BezierCurveTree_isLeaf( BX->left ) ) { - TesselateSubMatrix( BX->left, BY, - offStartX, offStartY, - BX->index, offEndY, - newFlagsX, newFlagsY, - left, vertex_1_0, tmp, - texLeft, texcoord_1_0, texTmp, - bTranspose ); - } - - if ( !BezierCurveTree_isLeaf( BX->right ) ) { - TesselateSubMatrix( BX->right, BY, - BX->index, offStartY, - offEndX, offEndY, - newFlagsX, newFlagsY, - tmp, vertex_1_1, right, - texTmp, texcoord_1_1, texRight, - bTranspose ); - } - } - -} - -void Patch::BuildTesselationCurves( EMatrixMajor major ){ - std::size_t nArrayStride, length, cross, strideU, strideV; - switch ( major ) - { - case ROW: - nArrayStride = 1; - length = ( m_width - 1 ) >> 1; - cross = m_height; - strideU = 1; - strideV = m_width; - - if ( !m_patchDef3 ) { - BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeU ); - } - - break; - case COL: - nArrayStride = m_tess.m_nArrayWidth; - length = ( m_height - 1 ) >> 1; - cross = m_width; - strideU = m_width; - strideV = 1; - - if ( !m_patchDef3 ) { - BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeV ); - } - - break; - default: - ERROR_MESSAGE( "neither row-major nor column-major" ); - return; - } - - Array arrayLength( length ); - Array pCurveTree( length ); - - std::size_t nArrayLength = 1; - - if ( m_patchDef3 ) { - for ( Array::iterator i = arrayLength.begin(); i != arrayLength.end(); ++i ) - { - *i = Array::value_type( ( major == ROW ) ? m_subdivisions_x : m_subdivisions_y ); - nArrayLength += *i; - } - } - else - { - // create a list of the horizontal control curves in each column of sub-patches - // adaptively tesselate each horizontal control curve in the list - // create a binary tree representing the combined tesselation of the list - for ( std::size_t i = 0; i != length; ++i ) - { - PatchControl* p1 = m_ctrlTransformed.data() + ( i * 2 * strideU ); - GSList* pCurveList = 0; - for ( std::size_t j = 0; j < cross; j += 2 ) - { - PatchControl* p2 = p1 + strideV; - PatchControl* p3 = p2 + strideV; - - // directly taken from one row of control points - { - BezierCurve* pCurve = new BezierCurve; - pCurve->crd = ( p1 + strideU )->m_vertex; - pCurve->left = p1->m_vertex; - pCurve->right = ( p1 + ( strideU << 1 ) )->m_vertex; - pCurveList = g_slist_prepend( pCurveList, pCurve ); - } - - if ( j + 2 >= cross ) { - break; - } - - // interpolated from three columns of control points - { - BezierCurve* pCurve = new BezierCurve; - pCurve->crd = vector3_mid( ( p1 + strideU )->m_vertex, ( p3 + strideU )->m_vertex ); - pCurve->left = vector3_mid( p1->m_vertex, p3->m_vertex ); - pCurve->right = vector3_mid( ( p1 + ( strideU << 1 ) )->m_vertex, ( p3 + ( strideU << 1 ) )->m_vertex ); - - pCurve->crd = vector3_mid( pCurve->crd, ( p2 + strideU )->m_vertex ); - pCurve->left = vector3_mid( pCurve->left, p2->m_vertex ); - pCurve->right = vector3_mid( pCurve->right, ( p2 + ( strideU << 1 ) )->m_vertex ); - pCurveList = g_slist_prepend( pCurveList, pCurve ); - } - - p1 = p3; - } - - pCurveTree[i] = new BezierCurveTree; - BezierCurveTree_FromCurveList( pCurveTree[i], pCurveList ); - for ( GSList* l = pCurveList; l != 0; l = g_slist_next( l ) ) - { - delete static_cast( ( *l ).data ); - } - g_slist_free( pCurveList ); - - // set up array indices for binary tree - // accumulate subarray width - arrayLength[i] = Array::value_type( BezierCurveTree_Setup( pCurveTree[i], nArrayLength, nArrayStride ) - ( nArrayLength - 1 ) ); - // accumulate total array width - nArrayLength += arrayLength[i]; - } - } - - switch ( major ) - { - case ROW: - m_tess.m_nArrayWidth = nArrayLength; - std::swap( m_tess.m_arrayWidth, arrayLength ); - - if ( !m_patchDef3 ) { - std::swap( m_tess.m_curveTreeU, pCurveTree ); - } - break; - case COL: - m_tess.m_nArrayHeight = nArrayLength; - std::swap( m_tess.m_arrayHeight, arrayLength ); - - if ( !m_patchDef3 ) { - std::swap( m_tess.m_curveTreeV, pCurveTree ); - } - break; - } -} - -inline void vertex_assign_ctrl( ArbitraryMeshVertex& vertex, const PatchControl& ctrl ){ - vertex.vertex = vertex3f_for_vector3( ctrl.m_vertex ); - vertex.texcoord = texcoord2f_for_vector2( ctrl.m_texcoord ); -} - -inline void vertex_clear_normal( ArbitraryMeshVertex& vertex ){ - vertex.normal = Normal3f( 0, 0, 0 ); - vertex.tangent = Normal3f( 0, 0, 0 ); - vertex.bitangent = Normal3f( 0, 0, 0 ); -} - -inline void tangents_remove_degenerate( Vector3 tangents[6], Vector2 textureTangents[6], unsigned int flags ){ - if ( flags & DEGEN_0a ) { - const std::size_t i = - ( flags & DEGEN_0b ) - ? ( flags & DEGEN_1a ) - ? ( flags & DEGEN_1b ) - ? ( flags & DEGEN_2a ) - ? 5 - : 4 - : 3 - : 2 - : 1; - tangents[0] = tangents[i]; - textureTangents[0] = textureTangents[i]; - } - if ( flags & DEGEN_0b ) { - const std::size_t i = - ( flags & DEGEN_0a ) - ? ( flags & DEGEN_1b ) - ? ( flags & DEGEN_1a ) - ? ( flags & DEGEN_2b ) - ? 4 - : 5 - : 2 - : 3 - : 0; - tangents[1] = tangents[i]; - textureTangents[1] = textureTangents[i]; - } - if ( flags & DEGEN_2a ) { - const std::size_t i = - ( flags & DEGEN_2b ) - ? ( flags & DEGEN_1a ) - ? ( flags & DEGEN_1b ) - ? ( flags & DEGEN_0a ) - ? 1 - : 0 - : 3 - : 2 - : 5; - tangents[4] = tangents[i]; - textureTangents[4] = textureTangents[i]; - } - if ( flags & DEGEN_2b ) { - const std::size_t i = - ( flags & DEGEN_2a ) - ? ( flags & DEGEN_1b ) - ? ( flags & DEGEN_1a ) - ? ( flags & DEGEN_0b ) - ? 0 - : 1 - : 2 - : 3 - : 4; - tangents[5] = tangents[i]; - textureTangents[5] = textureTangents[i]; - } -} - -void bestTangents00( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){ - if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate - if ( !( degenerateFlags & DEGEN_1a ) ) { // if this tangent is degenerate we cannot use it - index0 = 2; - index1 = 0; - } - else if ( !( degenerateFlags & DEGEN_0b ) ) { - index0 = 0; - index1 = 1; - } - else - { - index0 = 1; - index1 = 0; - } - } - else if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate - if ( degenerateFlags & DEGEN_0b ) { - index0 = 0; - index1 = 1; - } - else - { - index0 = 1; - index1 = 0; - } - } -} - -void bestTangents01( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){ - if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate - if ( !( degenerateFlags & DEGEN_1a ) ) { // if this tangent is degenerate we cannot use it - index0 = 2; - index1 = 1; - } - else if ( !( degenerateFlags & DEGEN_2b ) ) { - index0 = 4; - index1 = 0; - } - else - { - index0 = 5; - index1 = 1; - } - } - else if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate - if ( degenerateFlags & DEGEN_2b ) { - index0 = 4; - index1 = 0; - } - else - { - index0 = 5; - index1 = 1; - } - } -} - -void bestTangents10( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){ - if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate - if ( !( degenerateFlags & DEGEN_1b ) ) { // if this tangent is degenerate we cannot use it - index0 = 3; - index1 = 4; - } - else if ( !( degenerateFlags & DEGEN_0a ) ) { - index0 = 1; - index1 = 5; - } - else - { - index0 = 0; - index1 = 4; - } - } - else if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate - if ( degenerateFlags & DEGEN_0a ) { - index0 = 1; - index1 = 5; - } - else - { - index0 = 0; - index1 = 4; - } - } + BezierInterpolate2(texcoord_for_index(m_tess.m_vertices, offStartX + offStartY), + texcoord_0_0, + texcoord_for_index(m_tess.m_vertices, BX->index + offStartY), + texcoord_0_1, + texcoord_for_index(m_tess.m_vertices, offEndX + offStartY)); + + + BezierInterpolate2(texcoord_for_index(m_tess.m_vertices, offStartX + offEndY), + texcoord_2_0, + texcoord_for_index(m_tess.m_vertices, BX->index + offEndY), + texcoord_2_1, + texcoord_for_index(m_tess.m_vertices, offEndX + offEndY)); + + texTmp = texMid; + + BezierInterpolate2(texLeft, + texcoord_1_0, + texTmp, + texcoord_1_1, + texRight); + + if (!BezierCurveTree_isLeaf(BY)) { + texcoord_for_index(m_tess.m_vertices, BX->index + BY->index) = texTmp; + } + + + if (!BezierCurveTree_isLeaf(BX->left)) { + texcoord_for_index(m_tess.m_vertices, BX->left->index + offStartY) = texcoord_0_0; + texcoord_for_index(m_tess.m_vertices, BX->left->index + offEndY) = texcoord_2_0; + + if (!BezierCurveTree_isLeaf(BY)) { + texcoord_for_index(m_tess.m_vertices, BX->left->index + BY->index) = texcoord_1_0; + } + } + if (!BezierCurveTree_isLeaf(BX->right)) { + texcoord_for_index(m_tess.m_vertices, BX->right->index + offStartY) = texcoord_0_1; + texcoord_for_index(m_tess.m_vertices, BX->right->index + offEndY) = texcoord_2_1; + + if (!BezierCurveTree_isLeaf(BY)) { + texcoord_for_index(m_tess.m_vertices, BX->right->index + BY->index) = texcoord_1_1; + } + } + + + // verts + + BezierInterpolate3(vertex_for_index(m_tess.m_vertices, offStartX + offStartY), + vertex_0_0, + vertex_for_index(m_tess.m_vertices, BX->index + offStartY), + vertex_0_1, + vertex_for_index(m_tess.m_vertices, offEndX + offStartY)); + + + BezierInterpolate3(vertex_for_index(m_tess.m_vertices, offStartX + offEndY), + vertex_2_0, + vertex_for_index(m_tess.m_vertices, BX->index + offEndY), + vertex_2_1, + vertex_for_index(m_tess.m_vertices, offEndX + offEndY)); + + + tmp = mid; + + BezierInterpolate3(left, + vertex_1_0, + tmp, + vertex_1_1, + right); + + if (!BezierCurveTree_isLeaf(BY)) { + vertex_for_index(m_tess.m_vertices, BX->index + BY->index) = tmp; + } + + + if (!BezierCurveTree_isLeaf(BX->left)) { + vertex_for_index(m_tess.m_vertices, BX->left->index + offStartY) = vertex_0_0; + vertex_for_index(m_tess.m_vertices, BX->left->index + offEndY) = vertex_2_0; + + if (!BezierCurveTree_isLeaf(BY)) { + vertex_for_index(m_tess.m_vertices, BX->left->index + BY->index) = vertex_1_0; + } + } + if (!BezierCurveTree_isLeaf(BX->right)) { + vertex_for_index(m_tess.m_vertices, BX->right->index + offStartY) = vertex_0_1; + vertex_for_index(m_tess.m_vertices, BX->right->index + offEndY) = vertex_2_1; + + if (!BezierCurveTree_isLeaf(BY)) { + vertex_for_index(m_tess.m_vertices, BX->right->index + BY->index) = vertex_1_1; + } + } + + // normals + + if (nFlagsX & SPLIT) { + ArbitraryMeshVertex a, b, c; + Vector3 tangentU; + + if (!(nFlagsX & DEGEN_0a) || !(nFlagsX & DEGEN_0b)) { + tangentU = vector3_subtracted(vertex_0_1, vertex_0_0); + a.vertex = vertex3f_for_vector3(vertex_0_0); + a.texcoord = texcoord2f_for_vector2(texcoord_0_0); + c.vertex = vertex3f_for_vector3(vertex_0_1); + c.texcoord = texcoord2f_for_vector2(texcoord_0_1); + } else if (!(nFlagsX & DEGEN_1a) || !(nFlagsX & DEGEN_1b)) { + tangentU = vector3_subtracted(vertex_1_1, vertex_1_0); + a.vertex = vertex3f_for_vector3(vertex_1_0); + a.texcoord = texcoord2f_for_vector2(texcoord_1_0); + c.vertex = vertex3f_for_vector3(vertex_1_1); + c.texcoord = texcoord2f_for_vector2(texcoord_1_1); + } else { + tangentU = vector3_subtracted(vertex_2_1, vertex_2_0); + a.vertex = vertex3f_for_vector3(vertex_2_0); + a.texcoord = texcoord2f_for_vector2(texcoord_2_0); + c.vertex = vertex3f_for_vector3(vertex_2_1); + c.texcoord = texcoord2f_for_vector2(texcoord_2_1); + } + + Vector3 tangentV; + + if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_1a) && (nFlagsY & DEGEN_2a)) { + tangentV = vector3_subtracted(vertex_for_index(m_tess.m_vertices, BX->index + offEndY), tmp); + b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offEndY].vertex; + b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offEndY].texcoord; + } else { + tangentV = vector3_subtracted(tmp, vertex_for_index(m_tess.m_vertices, BX->index + offStartY)); + b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offStartY].vertex; + b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offStartY].texcoord; + } + + + Vector3 normal, s, t; + ArbitraryMeshVertex &v = m_tess.m_vertices[offStartY + BX->index]; + Vector3 &p = normal3f_to_vector3(v.normal); + Vector3 &ps = normal3f_to_vector3(v.tangent); + Vector3 &pt = normal3f_to_vector3(v.bitangent); + + if (bTranspose) { + normal = vector3_cross(tangentV, tangentU); + } else { + normal = vector3_cross(tangentU, tangentV); + } + normalise_safe(normal); + + ArbitraryMeshTriangle_calcTangents(a, b, c, s, t); + normalise_safe(s); + normalise_safe(t); + + if (nFlagsX & AVERAGE) { + p = vector3_normalised(vector3_added(p, normal)); + ps = vector3_normalised(vector3_added(ps, s)); + pt = vector3_normalised(vector3_added(pt, t)); + } else { + p = normal; + ps = s; + pt = t; + } + } + + { + ArbitraryMeshVertex a, b, c; + Vector3 tangentU; + + if (!(nFlagsX & DEGEN_2a) || !(nFlagsX & DEGEN_2b)) { + tangentU = vector3_subtracted(vertex_2_1, vertex_2_0); + a.vertex = vertex3f_for_vector3(vertex_2_0); + a.texcoord = texcoord2f_for_vector2(texcoord_2_0); + c.vertex = vertex3f_for_vector3(vertex_2_1); + c.texcoord = texcoord2f_for_vector2(texcoord_2_1); + } else if (!(nFlagsX & DEGEN_1a) || !(nFlagsX & DEGEN_1b)) { + tangentU = vector3_subtracted(vertex_1_1, vertex_1_0); + a.vertex = vertex3f_for_vector3(vertex_1_0); + a.texcoord = texcoord2f_for_vector2(texcoord_1_0); + c.vertex = vertex3f_for_vector3(vertex_1_1); + c.texcoord = texcoord2f_for_vector2(texcoord_1_1); + } else { + tangentU = vector3_subtracted(vertex_0_1, vertex_0_0); + a.vertex = vertex3f_for_vector3(vertex_0_0); + a.texcoord = texcoord2f_for_vector2(texcoord_0_0); + c.vertex = vertex3f_for_vector3(vertex_0_1); + c.texcoord = texcoord2f_for_vector2(texcoord_0_1); + } + + Vector3 tangentV; + + if ((nFlagsY & DEGEN_0b) && (nFlagsY & DEGEN_1b) && (nFlagsY & DEGEN_2b)) { + tangentV = vector3_subtracted(tmp, vertex_for_index(m_tess.m_vertices, BX->index + offStartY)); + b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offStartY].vertex; + b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offStartY].texcoord; + } else { + tangentV = vector3_subtracted(vertex_for_index(m_tess.m_vertices, BX->index + offEndY), tmp); + b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offEndY].vertex; + b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offEndY].texcoord; + } + + ArbitraryMeshVertex &v = m_tess.m_vertices[offEndY + BX->index]; + Vector3 &p = normal3f_to_vector3(v.normal); + Vector3 &ps = normal3f_to_vector3(v.tangent); + Vector3 &pt = normal3f_to_vector3(v.bitangent); + + if (bTranspose) { + p = vector3_cross(tangentV, tangentU); + } else { + p = vector3_cross(tangentU, tangentV); + } + normalise_safe(p); + + ArbitraryMeshTriangle_calcTangents(a, b, c, ps, pt); + normalise_safe(ps); + normalise_safe(pt); + } + } + + + newFlagsX = newFlagsY = 0; + + if ((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_0b)) { + newFlagsX |= DEGEN_0a; + newFlagsX |= DEGEN_0b; + } + if ((nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_1b)) { + newFlagsX |= DEGEN_1a; + newFlagsX |= DEGEN_1b; + } + if ((nFlagsX & DEGEN_2a) && (nFlagsX & DEGEN_2b)) { + newFlagsX |= DEGEN_2a; + newFlagsX |= DEGEN_2b; + } + if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_1a) && (nFlagsY & DEGEN_2a)) { + newFlagsY |= DEGEN_0a; + newFlagsY |= DEGEN_1a; + newFlagsY |= DEGEN_2a; + } + if ((nFlagsY & DEGEN_0b) && (nFlagsY & DEGEN_1b) && (nFlagsY & DEGEN_2b)) { + newFlagsY |= DEGEN_0b; + newFlagsY |= DEGEN_1b; + newFlagsY |= DEGEN_2b; + } + + + //if((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_2a)) { newFlagsX |= DEGEN_0a; newFlagsX |= DEGEN_1a; newFlagsX |= DEGEN_2a; } + //if((nFlagsX & DEGEN_0b) && (nFlagsX & DEGEN_1b) && (nFlagsX & DEGEN_2b)) { newFlagsX |= DEGEN_0b; newFlagsX |= DEGEN_1b; newFlagsX |= DEGEN_2b; } + + newFlagsX |= (nFlagsX & SPLIT); + newFlagsX |= (nFlagsX & AVERAGE); + + if (!BezierCurveTree_isLeaf(BY)) { + { + int nTemp = newFlagsY; + + if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_0b)) { + newFlagsY |= DEGEN_0a; + newFlagsY |= DEGEN_0b; + } + newFlagsY |= (nFlagsY & SPLIT); + newFlagsY |= (nFlagsY & AVERAGE); + + Vector3 &p = vertex_for_index(m_tess.m_vertices, BX->index + BY->index); + Vector3 vTemp(p); + + Vector2 &p2 = texcoord_for_index(m_tess.m_vertices, BX->index + BY->index); + Vector2 stTemp(p2); + + TesselateSubMatrix(BY, BX->left, + offStartY, offStartX, + offEndY, BX->index, + newFlagsY, newFlagsX, + vertex_0_0, vertex_1_0, vertex_2_0, + texcoord_0_0, texcoord_1_0, texcoord_2_0, + !bTranspose); + + newFlagsY = nTemp; + p = vTemp; + p2 = stTemp; + } + + if ((nFlagsY & DEGEN_2a) && (nFlagsY & DEGEN_2b)) { + newFlagsY |= DEGEN_2a; + newFlagsY |= DEGEN_2b; + } + + TesselateSubMatrix(BY, BX->right, + offStartY, BX->index, + offEndY, offEndX, + newFlagsY, newFlagsX, + vertex_0_1, vertex_1_1, vertex_2_1, + texcoord_0_1, texcoord_1_1, texcoord_2_1, + !bTranspose); + } else { + if (!BezierCurveTree_isLeaf(BX->left)) { + TesselateSubMatrix(BX->left, BY, + offStartX, offStartY, + BX->index, offEndY, + newFlagsX, newFlagsY, + left, vertex_1_0, tmp, + texLeft, texcoord_1_0, texTmp, + bTranspose); + } + + if (!BezierCurveTree_isLeaf(BX->right)) { + TesselateSubMatrix(BX->right, BY, + BX->index, offStartY, + offEndX, offEndY, + newFlagsX, newFlagsY, + tmp, vertex_1_1, right, + texTmp, texcoord_1_1, texRight, + bTranspose); + } + } + +} + +void Patch::BuildTesselationCurves(EMatrixMajor major) +{ + std::size_t nArrayStride, length, cross, strideU, strideV; + switch (major) { + case ROW: + nArrayStride = 1; + length = (m_width - 1) >> 1; + cross = m_height; + strideU = 1; + strideV = m_width; + + if (!m_patchDef3) { + BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU); + } + + break; + case COL: + nArrayStride = m_tess.m_nArrayWidth; + length = (m_height - 1) >> 1; + cross = m_width; + strideU = m_width; + strideV = 1; + + if (!m_patchDef3) { + BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV); + } + + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; + } + + Array arrayLength(length); + Array pCurveTree(length); + + std::size_t nArrayLength = 1; + + if (m_patchDef3) { + for (Array::iterator i = arrayLength.begin(); i != arrayLength.end(); ++i) { + *i = Array::value_type((major == ROW) ? m_subdivisions_x : m_subdivisions_y); + nArrayLength += *i; + } + } else { + // create a list of the horizontal control curves in each column of sub-patches + // adaptively tesselate each horizontal control curve in the list + // create a binary tree representing the combined tesselation of the list + for (std::size_t i = 0; i != length; ++i) { + PatchControl *p1 = m_ctrlTransformed.data() + (i * 2 * strideU); + GSList *pCurveList = 0; + for (std::size_t j = 0; j < cross; j += 2) { + PatchControl *p2 = p1 + strideV; + PatchControl *p3 = p2 + strideV; + + // directly taken from one row of control points + { + BezierCurve *pCurve = new BezierCurve; + pCurve->crd = (p1 + strideU)->m_vertex; + pCurve->left = p1->m_vertex; + pCurve->right = (p1 + (strideU << 1))->m_vertex; + pCurveList = g_slist_prepend(pCurveList, pCurve); + } + + if (j + 2 >= cross) { + break; + } + + // interpolated from three columns of control points + { + BezierCurve *pCurve = new BezierCurve; + pCurve->crd = vector3_mid((p1 + strideU)->m_vertex, (p3 + strideU)->m_vertex); + pCurve->left = vector3_mid(p1->m_vertex, p3->m_vertex); + pCurve->right = vector3_mid((p1 + (strideU << 1))->m_vertex, (p3 + (strideU << 1))->m_vertex); + + pCurve->crd = vector3_mid(pCurve->crd, (p2 + strideU)->m_vertex); + pCurve->left = vector3_mid(pCurve->left, p2->m_vertex); + pCurve->right = vector3_mid(pCurve->right, (p2 + (strideU << 1))->m_vertex); + pCurveList = g_slist_prepend(pCurveList, pCurve); + } + + p1 = p3; + } + + pCurveTree[i] = new BezierCurveTree; + BezierCurveTree_FromCurveList(pCurveTree[i], pCurveList); + for (GSList *l = pCurveList; l != 0; l = g_slist_next(l)) { + delete static_cast((*l).data ); + } + g_slist_free(pCurveList); + + // set up array indices for binary tree + // accumulate subarray width + arrayLength[i] = Array::value_type( + BezierCurveTree_Setup(pCurveTree[i], nArrayLength, nArrayStride) - (nArrayLength - 1)); + // accumulate total array width + nArrayLength += arrayLength[i]; + } + } + + switch (major) { + case ROW: + m_tess.m_nArrayWidth = nArrayLength; + std::swap(m_tess.m_arrayWidth, arrayLength); + + if (!m_patchDef3) { + std::swap(m_tess.m_curveTreeU, pCurveTree); + } + break; + case COL: + m_tess.m_nArrayHeight = nArrayLength; + std::swap(m_tess.m_arrayHeight, arrayLength); + + if (!m_patchDef3) { + std::swap(m_tess.m_curveTreeV, pCurveTree); + } + break; + } +} + +inline void vertex_assign_ctrl(ArbitraryMeshVertex &vertex, const PatchControl &ctrl) +{ + vertex.vertex = vertex3f_for_vector3(ctrl.m_vertex); + vertex.texcoord = texcoord2f_for_vector2(ctrl.m_texcoord); } -void bestTangents11( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){ - if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate - if ( !( degenerateFlags & DEGEN_1b ) ) { // if this tangent is degenerate we cannot use it - index0 = 3; - index1 = 5; - } - else if ( !( degenerateFlags & DEGEN_2a ) ) { - index0 = 5; - index1 = 4; - } - else - { - index0 = 4; - index1 = 5; - } - } - else if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate - if ( degenerateFlags & DEGEN_2a ) { - index0 = 5; - index1 = 4; - } - else - { - index0 = 4; - index1 = 5; - } - } +inline void vertex_clear_normal(ArbitraryMeshVertex &vertex) +{ + vertex.normal = Normal3f(0, 0, 0); + vertex.tangent = Normal3f(0, 0, 0); + vertex.bitangent = Normal3f(0, 0, 0); } -void Patch::accumulateVertexTangentSpace( std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6], Vector2 tangentT[6], std::size_t index0, std::size_t index1 ){ - { - Vector3 normal( vector3_cross( tangentX[index0], tangentY[index1] ) ); - if ( !vector3_equal( normal, g_vector3_identity ) ) { - vector3_add( normal_for_index( m_tess.m_vertices, index ), vector3_normalised( normal ) ); - } - } - - { - ArbitraryMeshVertex a, b, c; - a.vertex = Vertex3f( 0, 0, 0 ); - a.texcoord = TexCoord2f( 0, 0 ); - b.vertex = vertex3f_for_vector3( tangentX[index0] ); - b.texcoord = texcoord2f_for_vector2( tangentS[index0] ); - c.vertex = vertex3f_for_vector3( tangentY[index1] ); - c.texcoord = texcoord2f_for_vector2( tangentT[index1] ); - - Vector3 s, t; - ArbitraryMeshTriangle_calcTangents( a, b, c, s, t ); - if ( !vector3_equal( s, g_vector3_identity ) ) { - vector3_add( tangent_for_index( m_tess.m_vertices, index ), vector3_normalised( s ) ); - } - if ( !vector3_equal( t, g_vector3_identity ) ) { - vector3_add( bitangent_for_index( m_tess.m_vertices, index ), vector3_normalised( t ) ); - } - } +inline void tangents_remove_degenerate(Vector3 tangents[6], Vector2 textureTangents[6], unsigned int flags) +{ + if (flags & DEGEN_0a) { + const std::size_t i = + (flags & DEGEN_0b) + ? (flags & DEGEN_1a) + ? (flags & DEGEN_1b) + ? (flags & DEGEN_2a) + ? 5 + : 4 + : 3 + : 2 + : 1; + tangents[0] = tangents[i]; + textureTangents[0] = textureTangents[i]; + } + if (flags & DEGEN_0b) { + const std::size_t i = + (flags & DEGEN_0a) + ? (flags & DEGEN_1b) + ? (flags & DEGEN_1a) + ? (flags & DEGEN_2b) + ? 4 + : 5 + : 2 + : 3 + : 0; + tangents[1] = tangents[i]; + textureTangents[1] = textureTangents[i]; + } + if (flags & DEGEN_2a) { + const std::size_t i = + (flags & DEGEN_2b) + ? (flags & DEGEN_1a) + ? (flags & DEGEN_1b) + ? (flags & DEGEN_0a) + ? 1 + : 0 + : 3 + : 2 + : 5; + tangents[4] = tangents[i]; + textureTangents[4] = textureTangents[i]; + } + if (flags & DEGEN_2b) { + const std::size_t i = + (flags & DEGEN_2a) + ? (flags & DEGEN_1b) + ? (flags & DEGEN_1a) + ? (flags & DEGEN_0b) + ? 0 + : 1 + : 2 + : 3 + : 4; + tangents[5] = tangents[i]; + textureTangents[5] = textureTangents[i]; + } +} + +void bestTangents00(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1) +{ + if (fabs(dot + length) < 0.001) { // opposing direction = degenerate + if (!(degenerateFlags & DEGEN_1a)) { // if this tangent is degenerate we cannot use it + index0 = 2; + index1 = 0; + } else if (!(degenerateFlags & DEGEN_0b)) { + index0 = 0; + index1 = 1; + } else { + index0 = 1; + index1 = 0; + } + } else if (fabs(dot - length) < 0.001) { // same direction = degenerate + if (degenerateFlags & DEGEN_0b) { + index0 = 0; + index1 = 1; + } else { + index0 = 1; + index1 = 0; + } + } +} + +void bestTangents01(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1) +{ + if (fabs(dot - length) < 0.001) { // same direction = degenerate + if (!(degenerateFlags & DEGEN_1a)) { // if this tangent is degenerate we cannot use it + index0 = 2; + index1 = 1; + } else if (!(degenerateFlags & DEGEN_2b)) { + index0 = 4; + index1 = 0; + } else { + index0 = 5; + index1 = 1; + } + } else if (fabs(dot + length) < 0.001) { // opposing direction = degenerate + if (degenerateFlags & DEGEN_2b) { + index0 = 4; + index1 = 0; + } else { + index0 = 5; + index1 = 1; + } + } +} + +void bestTangents10(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1) +{ + if (fabs(dot - length) < 0.001) { // same direction = degenerate + if (!(degenerateFlags & DEGEN_1b)) { // if this tangent is degenerate we cannot use it + index0 = 3; + index1 = 4; + } else if (!(degenerateFlags & DEGEN_0a)) { + index0 = 1; + index1 = 5; + } else { + index0 = 0; + index1 = 4; + } + } else if (fabs(dot + length) < 0.001) { // opposing direction = degenerate + if (degenerateFlags & DEGEN_0a) { + index0 = 1; + index1 = 5; + } else { + index0 = 0; + index1 = 4; + } + } +} + +void bestTangents11(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1) +{ + if (fabs(dot + length) < 0.001) { // opposing direction = degenerate + if (!(degenerateFlags & DEGEN_1b)) { // if this tangent is degenerate we cannot use it + index0 = 3; + index1 = 5; + } else if (!(degenerateFlags & DEGEN_2a)) { + index0 = 5; + index1 = 4; + } else { + index0 = 4; + index1 = 5; + } + } else if (fabs(dot - length) < 0.001) { // same direction = degenerate + if (degenerateFlags & DEGEN_2a) { + index0 = 5; + index1 = 4; + } else { + index0 = 4; + index1 = 5; + } + } +} + +void +Patch::accumulateVertexTangentSpace(std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6], + Vector2 tangentT[6], std::size_t index0, std::size_t index1) +{ + { + Vector3 normal(vector3_cross(tangentX[index0], tangentY[index1])); + if (!vector3_equal(normal, g_vector3_identity)) { + vector3_add(normal_for_index(m_tess.m_vertices, index), vector3_normalised(normal)); + } + } + + { + ArbitraryMeshVertex a, b, c; + a.vertex = Vertex3f(0, 0, 0); + a.texcoord = TexCoord2f(0, 0); + b.vertex = vertex3f_for_vector3(tangentX[index0]); + b.texcoord = texcoord2f_for_vector2(tangentS[index0]); + c.vertex = vertex3f_for_vector3(tangentY[index1]); + c.texcoord = texcoord2f_for_vector2(tangentT[index1]); + + Vector3 s, t; + ArbitraryMeshTriangle_calcTangents(a, b, c, s, t); + if (!vector3_equal(s, g_vector3_identity)) { + vector3_add(tangent_for_index(m_tess.m_vertices, index), vector3_normalised(s)); + } + if (!vector3_equal(t, g_vector3_identity)) { + vector3_add(bitangent_for_index(m_tess.m_vertices, index), vector3_normalised(t)); + } + } } const std::size_t PATCH_MAX_VERTEX_ARRAY = 1048576; -void Patch::BuildVertexArray(){ - const std::size_t strideU = 1; - const std::size_t strideV = m_width; - - const std::size_t numElems = m_tess.m_nArrayWidth * m_tess.m_nArrayHeight; // total number of elements in vertex array - - const bool bWidthStrips = ( m_tess.m_nArrayWidth >= m_tess.m_nArrayHeight ); // decide if horizontal strips are longer than vertical - - - // allocate vertex, normal, texcoord and primitive-index arrays - m_tess.m_vertices.resize( numElems ); - m_tess.m_indices.resize( m_tess.m_nArrayWidth * 2 * ( m_tess.m_nArrayHeight - 1 ) ); - - // set up strip indices - if ( bWidthStrips ) { - m_tess.m_numStrips = m_tess.m_nArrayHeight - 1; - m_tess.m_lenStrips = m_tess.m_nArrayWidth * 2; - - for ( std::size_t i = 0; i < m_tess.m_nArrayWidth; i++ ) - { - for ( std::size_t j = 0; j < m_tess.m_numStrips; j++ ) - { - m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2] = RenderIndex( j * m_tess.m_nArrayWidth + i ); - m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2 + 1] = RenderIndex( ( j + 1 ) * m_tess.m_nArrayWidth + i ); - // reverse because radiant uses CULL_FRONT - //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(j*m_tess.m_nArrayWidth+i); - //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i); - } - } - } - else - { - m_tess.m_numStrips = m_tess.m_nArrayWidth - 1; - m_tess.m_lenStrips = m_tess.m_nArrayHeight * 2; - - for ( std::size_t i = 0; i < m_tess.m_nArrayHeight; i++ ) - { - for ( std::size_t j = 0; j < m_tess.m_numStrips; j++ ) - { - m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2] = RenderIndex( ( ( m_tess.m_nArrayHeight - 1 ) - i ) * m_tess.m_nArrayWidth + j ); - m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2 + 1] = RenderIndex( ( ( m_tess.m_nArrayHeight - 1 ) - i ) * m_tess.m_nArrayWidth + j + 1 ); - // reverse because radiant uses CULL_FRONT - //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j); - //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1); - - } - } - } - - { - PatchControlIter pCtrl = m_ctrlTransformed.data(); - for ( std::size_t j = 0, offStartY = 0; j + 1 < m_height; j += 2, pCtrl += ( strideU + strideV ) ) - { - // set up array offsets for this sub-patch - const bool leafY = ( m_patchDef3 ) ? false : BezierCurveTree_isLeaf( m_tess.m_curveTreeV[j >> 1] ); - const std::size_t offMidY = ( m_patchDef3 ) ? 0 : m_tess.m_curveTreeV[j >> 1]->index; - const std::size_t widthY = m_tess.m_arrayHeight[j >> 1] * m_tess.m_nArrayWidth; - const std::size_t offEndY = offStartY + widthY; - - for ( std::size_t i = 0, offStartX = 0; i + 1 < m_width; i += 2, pCtrl += ( strideU << 1 ) ) - { - const bool leafX = ( m_patchDef3 ) ? false : BezierCurveTree_isLeaf( m_tess.m_curveTreeU[i >> 1] ); - const std::size_t offMidX = ( m_patchDef3 ) ? 0 : m_tess.m_curveTreeU[i >> 1]->index; - const std::size_t widthX = m_tess.m_arrayWidth[i >> 1]; - const std::size_t offEndX = offStartX + widthX; - - PatchControl *subMatrix[3][3]; - subMatrix[0][0] = pCtrl; - subMatrix[0][1] = subMatrix[0][0] + strideU; - subMatrix[0][2] = subMatrix[0][1] + strideU; - subMatrix[1][0] = subMatrix[0][0] + strideV; - subMatrix[1][1] = subMatrix[1][0] + strideU; - subMatrix[1][2] = subMatrix[1][1] + strideU; - subMatrix[2][0] = subMatrix[1][0] + strideV; - subMatrix[2][1] = subMatrix[2][0] + strideU; - subMatrix[2][2] = subMatrix[2][1] + strideU; - - // assign on-patch control points to vertex array - if ( i == 0 && j == 0 ) { - vertex_clear_normal( m_tess.m_vertices[offStartX + offStartY] ); - } - vertex_assign_ctrl( m_tess.m_vertices[offStartX + offStartY], *subMatrix[0][0] ); - if ( j == 0 ) { - vertex_clear_normal( m_tess.m_vertices[offEndX + offStartY] ); - } - vertex_assign_ctrl( m_tess.m_vertices[offEndX + offStartY], *subMatrix[0][2] ); - if ( i == 0 ) { - vertex_clear_normal( m_tess.m_vertices[offStartX + offEndY] ); - } - vertex_assign_ctrl( m_tess.m_vertices[offStartX + offEndY], *subMatrix[2][0] ); - - vertex_clear_normal( m_tess.m_vertices[offEndX + offEndY] ); - vertex_assign_ctrl( m_tess.m_vertices[offEndX + offEndY], *subMatrix[2][2] ); - - if ( !m_patchDef3 ) { - // assign remaining control points to vertex array - if ( !leafX ) { - vertex_assign_ctrl( m_tess.m_vertices[offMidX + offStartY], *subMatrix[0][1] ); - vertex_assign_ctrl( m_tess.m_vertices[offMidX + offEndY], *subMatrix[2][1] ); - } - if ( !leafY ) { - vertex_assign_ctrl( m_tess.m_vertices[offStartX + offMidY], *subMatrix[1][0] ); - vertex_assign_ctrl( m_tess.m_vertices[offEndX + offMidY], *subMatrix[1][2] ); - - if ( !leafX ) { - vertex_assign_ctrl( m_tess.m_vertices[offMidX + offMidY], *subMatrix[1][1] ); - } - } - } - - // test all 12 edges for degeneracy - unsigned int nFlagsX = subarray_get_degen( pCtrl, strideU, strideV ); - unsigned int nFlagsY = subarray_get_degen( pCtrl, strideV, strideU ); - Vector3 tangentX[6], tangentY[6]; - Vector2 tangentS[6], tangentT[6]; - - // set up tangents for each of the 12 edges if they were not degenerate - if ( !( nFlagsX & DEGEN_0a ) ) { - tangentX[0] = vector3_subtracted( subMatrix[0][1]->m_vertex, subMatrix[0][0]->m_vertex ); - tangentS[0] = vector2_subtracted( subMatrix[0][1]->m_texcoord, subMatrix[0][0]->m_texcoord ); - } - if ( !( nFlagsX & DEGEN_0b ) ) { - tangentX[1] = vector3_subtracted( subMatrix[0][2]->m_vertex, subMatrix[0][1]->m_vertex ); - tangentS[1] = vector2_subtracted( subMatrix[0][2]->m_texcoord, subMatrix[0][1]->m_texcoord ); - } - if ( !( nFlagsX & DEGEN_1a ) ) { - tangentX[2] = vector3_subtracted( subMatrix[1][1]->m_vertex, subMatrix[1][0]->m_vertex ); - tangentS[2] = vector2_subtracted( subMatrix[1][1]->m_texcoord, subMatrix[1][0]->m_texcoord ); - } - if ( !( nFlagsX & DEGEN_1b ) ) { - tangentX[3] = vector3_subtracted( subMatrix[1][2]->m_vertex, subMatrix[1][1]->m_vertex ); - tangentS[3] = vector2_subtracted( subMatrix[1][2]->m_texcoord, subMatrix[1][1]->m_texcoord ); - } - if ( !( nFlagsX & DEGEN_2a ) ) { - tangentX[4] = vector3_subtracted( subMatrix[2][1]->m_vertex, subMatrix[2][0]->m_vertex ); - tangentS[4] = vector2_subtracted( subMatrix[2][1]->m_texcoord, subMatrix[2][0]->m_texcoord ); - } - if ( !( nFlagsX & DEGEN_2b ) ) { - tangentX[5] = vector3_subtracted( subMatrix[2][2]->m_vertex, subMatrix[2][1]->m_vertex ); - tangentS[5] = vector2_subtracted( subMatrix[2][2]->m_texcoord, subMatrix[2][1]->m_texcoord ); - } - - if ( !( nFlagsY & DEGEN_0a ) ) { - tangentY[0] = vector3_subtracted( subMatrix[1][0]->m_vertex, subMatrix[0][0]->m_vertex ); - tangentT[0] = vector2_subtracted( subMatrix[1][0]->m_texcoord, subMatrix[0][0]->m_texcoord ); - } - if ( !( nFlagsY & DEGEN_0b ) ) { - tangentY[1] = vector3_subtracted( subMatrix[2][0]->m_vertex, subMatrix[1][0]->m_vertex ); - tangentT[1] = vector2_subtracted( subMatrix[2][0]->m_texcoord, subMatrix[1][0]->m_texcoord ); - } - if ( !( nFlagsY & DEGEN_1a ) ) { - tangentY[2] = vector3_subtracted( subMatrix[1][1]->m_vertex, subMatrix[0][1]->m_vertex ); - tangentT[2] = vector2_subtracted( subMatrix[1][1]->m_texcoord, subMatrix[0][1]->m_texcoord ); - } - if ( !( nFlagsY & DEGEN_1b ) ) { - tangentY[3] = vector3_subtracted( subMatrix[2][1]->m_vertex, subMatrix[1][1]->m_vertex ); - tangentT[3] = vector2_subtracted( subMatrix[2][1]->m_texcoord, subMatrix[1][1]->m_texcoord ); - } - if ( !( nFlagsY & DEGEN_2a ) ) { - tangentY[4] = vector3_subtracted( subMatrix[1][2]->m_vertex, subMatrix[0][2]->m_vertex ); - tangentT[4] = vector2_subtracted( subMatrix[1][2]->m_texcoord, subMatrix[0][2]->m_texcoord ); - } - if ( !( nFlagsY & DEGEN_2b ) ) { - tangentY[5] = vector3_subtracted( subMatrix[2][2]->m_vertex, subMatrix[1][2]->m_vertex ); - tangentT[5] = vector2_subtracted( subMatrix[2][2]->m_texcoord, subMatrix[1][2]->m_texcoord ); - } - - // set up remaining edge tangents by borrowing the tangent from the closest parallel non-degenerate edge - tangents_remove_degenerate( tangentX, tangentS, nFlagsX ); - tangents_remove_degenerate( tangentY, tangentT, nFlagsY ); - - { - // x=0, y=0 - std::size_t index = offStartX + offStartY; - std::size_t index0 = 0; - std::size_t index1 = 0; - - double dot = vector3_dot( tangentX[index0], tangentY[index1] ); - double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] ); - - bestTangents00( nFlagsX, dot, length, index0, index1 ); - - accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 ); - } - - { - // x=1, y=0 - std::size_t index = offEndX + offStartY; - std::size_t index0 = 1; - std::size_t index1 = 4; - - double dot = vector3_dot( tangentX[index0],tangentY[index1] ); - double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] ); - - bestTangents10( nFlagsX, dot, length, index0, index1 ); - - accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 ); - } - - { - // x=0, y=1 - std::size_t index = offStartX + offEndY; - std::size_t index0 = 4; - std::size_t index1 = 1; - - double dot = vector3_dot( tangentX[index0], tangentY[index1] ); - double length = vector3_length( tangentX[index1] ) * vector3_length( tangentY[index1] ); - - bestTangents01( nFlagsX, dot, length, index0, index1 ); - - accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 ); - } - - { - // x=1, y=1 - std::size_t index = offEndX + offEndY; - std::size_t index0 = 5; - std::size_t index1 = 5; - - double dot = vector3_dot( tangentX[index0],tangentY[index1] ); - double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] ); - - bestTangents11( nFlagsX, dot, length, index0, index1 ); - - accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 ); - } - - //normalise normals that won't be accumulated again - if ( i != 0 || j != 0 ) { - normalise_safe( normal_for_index( m_tess.m_vertices, offStartX + offStartY ) ); - normalise_safe( tangent_for_index( m_tess.m_vertices, offStartX + offStartY ) ); - normalise_safe( bitangent_for_index( m_tess.m_vertices, offStartX + offStartY ) ); - } - if ( i + 3 == m_width ) { - normalise_safe( normal_for_index( m_tess.m_vertices, offEndX + offStartY ) ); - normalise_safe( tangent_for_index( m_tess.m_vertices, offEndX + offStartY ) ); - normalise_safe( bitangent_for_index( m_tess.m_vertices, offEndX + offStartY ) ); - } - if ( j + 3 == m_height ) { - normalise_safe( normal_for_index( m_tess.m_vertices, offStartX + offEndY ) ); - normalise_safe( tangent_for_index( m_tess.m_vertices, offStartX + offEndY ) ); - normalise_safe( bitangent_for_index( m_tess.m_vertices, offStartX + offEndY ) ); - } - if ( i + 3 == m_width && j + 3 == m_height ) { - normalise_safe( normal_for_index( m_tess.m_vertices, offEndX + offEndY ) ); - normalise_safe( tangent_for_index( m_tess.m_vertices, offEndX + offEndY ) ); - normalise_safe( bitangent_for_index( m_tess.m_vertices, offEndX + offEndY ) ); - } - - // set flags to average normals between shared edges - if ( j != 0 ) { - nFlagsX |= AVERAGE; - } - if ( i != 0 ) { - nFlagsY |= AVERAGE; - } - // set flags to save evaluating shared edges twice - nFlagsX |= SPLIT; - nFlagsY |= SPLIT; - - // if the patch is curved.. tesselate recursively - // use the relevant control curves for this sub-patch - if ( m_patchDef3 ) { - TesselateSubMatrixFixed( m_tess.m_vertices.data() + offStartX + offStartY, 1, m_tess.m_nArrayWidth, nFlagsX, nFlagsY, subMatrix ); - } - else - { - if ( !leafX ) { - TesselateSubMatrix( m_tess.m_curveTreeU[i >> 1], m_tess.m_curveTreeV[j >> 1], - offStartX, offStartY, offEndX, offEndY, // array offsets - nFlagsX, nFlagsY, - subMatrix[1][0]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[1][2]->m_vertex, - subMatrix[1][0]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[1][2]->m_texcoord, - false ); - } - else if ( !leafY ) { - TesselateSubMatrix( m_tess.m_curveTreeV[j >> 1], m_tess.m_curveTreeU[i >> 1], - offStartY, offStartX, offEndY, offEndX, // array offsets - nFlagsY, nFlagsX, - subMatrix[0][1]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[2][1]->m_vertex, - subMatrix[0][1]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[2][1]->m_texcoord, - true ); - } - } - - offStartX = offEndX; - } - offStartY = offEndY; - } - } -} - - - -class PatchFilterWrapper : public Filter +void Patch::BuildVertexArray() { -bool m_active; -bool m_invert; -PatchFilter& m_filter; + const std::size_t strideU = 1; + const std::size_t strideV = m_width; + + const std::size_t numElems = + m_tess.m_nArrayWidth * m_tess.m_nArrayHeight; // total number of elements in vertex array + + const bool bWidthStrips = (m_tess.m_nArrayWidth >= + m_tess.m_nArrayHeight); // decide if horizontal strips are longer than vertical + + + // allocate vertex, normal, texcoord and primitive-index arrays + m_tess.m_vertices.resize(numElems); + m_tess.m_indices.resize(m_tess.m_nArrayWidth * 2 * (m_tess.m_nArrayHeight - 1)); + + // set up strip indices + if (bWidthStrips) { + m_tess.m_numStrips = m_tess.m_nArrayHeight - 1; + m_tess.m_lenStrips = m_tess.m_nArrayWidth * 2; + + for (std::size_t i = 0; i < m_tess.m_nArrayWidth; i++) { + for (std::size_t j = 0; j < m_tess.m_numStrips; j++) { + m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2] = RenderIndex(j * m_tess.m_nArrayWidth + i); + m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2 + 1] = RenderIndex( + (j + 1) * m_tess.m_nArrayWidth + i); + // reverse because radiant uses CULL_FRONT + //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(j*m_tess.m_nArrayWidth+i); + //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i); + } + } + } else { + m_tess.m_numStrips = m_tess.m_nArrayWidth - 1; + m_tess.m_lenStrips = m_tess.m_nArrayHeight * 2; + + for (std::size_t i = 0; i < m_tess.m_nArrayHeight; i++) { + for (std::size_t j = 0; j < m_tess.m_numStrips; j++) { + m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2] = RenderIndex( + ((m_tess.m_nArrayHeight - 1) - i) * m_tess.m_nArrayWidth + j); + m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2 + 1] = RenderIndex( + ((m_tess.m_nArrayHeight - 1) - i) * m_tess.m_nArrayWidth + j + 1); + // reverse because radiant uses CULL_FRONT + //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j); + //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1); + + } + } + } + + { + PatchControlIter pCtrl = m_ctrlTransformed.data(); + for (std::size_t j = 0, offStartY = 0; j + 1 < m_height; j += 2, pCtrl += (strideU + strideV)) { + // set up array offsets for this sub-patch + const bool leafY = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeV[j >> 1]); + const std::size_t offMidY = (m_patchDef3) ? 0 : m_tess.m_curveTreeV[j >> 1]->index; + const std::size_t widthY = m_tess.m_arrayHeight[j >> 1] * m_tess.m_nArrayWidth; + const std::size_t offEndY = offStartY + widthY; + + for (std::size_t i = 0, offStartX = 0; i + 1 < m_width; i += 2, pCtrl += (strideU << 1)) { + const bool leafX = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i >> 1]); + const std::size_t offMidX = (m_patchDef3) ? 0 : m_tess.m_curveTreeU[i >> 1]->index; + const std::size_t widthX = m_tess.m_arrayWidth[i >> 1]; + const std::size_t offEndX = offStartX + widthX; + + PatchControl *subMatrix[3][3]; + subMatrix[0][0] = pCtrl; + subMatrix[0][1] = subMatrix[0][0] + strideU; + subMatrix[0][2] = subMatrix[0][1] + strideU; + subMatrix[1][0] = subMatrix[0][0] + strideV; + subMatrix[1][1] = subMatrix[1][0] + strideU; + subMatrix[1][2] = subMatrix[1][1] + strideU; + subMatrix[2][0] = subMatrix[1][0] + strideV; + subMatrix[2][1] = subMatrix[2][0] + strideU; + subMatrix[2][2] = subMatrix[2][1] + strideU; + + // assign on-patch control points to vertex array + if (i == 0 && j == 0) { + vertex_clear_normal(m_tess.m_vertices[offStartX + offStartY]); + } + vertex_assign_ctrl(m_tess.m_vertices[offStartX + offStartY], *subMatrix[0][0]); + if (j == 0) { + vertex_clear_normal(m_tess.m_vertices[offEndX + offStartY]); + } + vertex_assign_ctrl(m_tess.m_vertices[offEndX + offStartY], *subMatrix[0][2]); + if (i == 0) { + vertex_clear_normal(m_tess.m_vertices[offStartX + offEndY]); + } + vertex_assign_ctrl(m_tess.m_vertices[offStartX + offEndY], *subMatrix[2][0]); + + vertex_clear_normal(m_tess.m_vertices[offEndX + offEndY]); + vertex_assign_ctrl(m_tess.m_vertices[offEndX + offEndY], *subMatrix[2][2]); + + if (!m_patchDef3) { + // assign remaining control points to vertex array + if (!leafX) { + vertex_assign_ctrl(m_tess.m_vertices[offMidX + offStartY], *subMatrix[0][1]); + vertex_assign_ctrl(m_tess.m_vertices[offMidX + offEndY], *subMatrix[2][1]); + } + if (!leafY) { + vertex_assign_ctrl(m_tess.m_vertices[offStartX + offMidY], *subMatrix[1][0]); + vertex_assign_ctrl(m_tess.m_vertices[offEndX + offMidY], *subMatrix[1][2]); + + if (!leafX) { + vertex_assign_ctrl(m_tess.m_vertices[offMidX + offMidY], *subMatrix[1][1]); + } + } + } + + // test all 12 edges for degeneracy + unsigned int nFlagsX = subarray_get_degen(pCtrl, strideU, strideV); + unsigned int nFlagsY = subarray_get_degen(pCtrl, strideV, strideU); + Vector3 tangentX[6], tangentY[6]; + Vector2 tangentS[6], tangentT[6]; + + // set up tangents for each of the 12 edges if they were not degenerate + if (!(nFlagsX & DEGEN_0a)) { + tangentX[0] = vector3_subtracted(subMatrix[0][1]->m_vertex, subMatrix[0][0]->m_vertex); + tangentS[0] = vector2_subtracted(subMatrix[0][1]->m_texcoord, subMatrix[0][0]->m_texcoord); + } + if (!(nFlagsX & DEGEN_0b)) { + tangentX[1] = vector3_subtracted(subMatrix[0][2]->m_vertex, subMatrix[0][1]->m_vertex); + tangentS[1] = vector2_subtracted(subMatrix[0][2]->m_texcoord, subMatrix[0][1]->m_texcoord); + } + if (!(nFlagsX & DEGEN_1a)) { + tangentX[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[1][0]->m_vertex); + tangentS[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[1][0]->m_texcoord); + } + if (!(nFlagsX & DEGEN_1b)) { + tangentX[3] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[1][1]->m_vertex); + tangentS[3] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[1][1]->m_texcoord); + } + if (!(nFlagsX & DEGEN_2a)) { + tangentX[4] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[2][0]->m_vertex); + tangentS[4] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[2][0]->m_texcoord); + } + if (!(nFlagsX & DEGEN_2b)) { + tangentX[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[2][1]->m_vertex); + tangentS[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[2][1]->m_texcoord); + } + + if (!(nFlagsY & DEGEN_0a)) { + tangentY[0] = vector3_subtracted(subMatrix[1][0]->m_vertex, subMatrix[0][0]->m_vertex); + tangentT[0] = vector2_subtracted(subMatrix[1][0]->m_texcoord, subMatrix[0][0]->m_texcoord); + } + if (!(nFlagsY & DEGEN_0b)) { + tangentY[1] = vector3_subtracted(subMatrix[2][0]->m_vertex, subMatrix[1][0]->m_vertex); + tangentT[1] = vector2_subtracted(subMatrix[2][0]->m_texcoord, subMatrix[1][0]->m_texcoord); + } + if (!(nFlagsY & DEGEN_1a)) { + tangentY[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[0][1]->m_vertex); + tangentT[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[0][1]->m_texcoord); + } + if (!(nFlagsY & DEGEN_1b)) { + tangentY[3] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[1][1]->m_vertex); + tangentT[3] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[1][1]->m_texcoord); + } + if (!(nFlagsY & DEGEN_2a)) { + tangentY[4] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[0][2]->m_vertex); + tangentT[4] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[0][2]->m_texcoord); + } + if (!(nFlagsY & DEGEN_2b)) { + tangentY[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[1][2]->m_vertex); + tangentT[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[1][2]->m_texcoord); + } + + // set up remaining edge tangents by borrowing the tangent from the closest parallel non-degenerate edge + tangents_remove_degenerate(tangentX, tangentS, nFlagsX); + tangents_remove_degenerate(tangentY, tangentT, nFlagsY); + + { + // x=0, y=0 + std::size_t index = offStartX + offStartY; + std::size_t index0 = 0; + std::size_t index1 = 0; + + double dot = vector3_dot(tangentX[index0], tangentY[index1]); + double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]); + + bestTangents00(nFlagsX, dot, length, index0, index1); + + accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1); + } + + { + // x=1, y=0 + std::size_t index = offEndX + offStartY; + std::size_t index0 = 1; + std::size_t index1 = 4; + + double dot = vector3_dot(tangentX[index0], tangentY[index1]); + double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]); + + bestTangents10(nFlagsX, dot, length, index0, index1); + + accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1); + } + + { + // x=0, y=1 + std::size_t index = offStartX + offEndY; + std::size_t index0 = 4; + std::size_t index1 = 1; + + double dot = vector3_dot(tangentX[index0], tangentY[index1]); + double length = vector3_length(tangentX[index1]) * vector3_length(tangentY[index1]); + + bestTangents01(nFlagsX, dot, length, index0, index1); + + accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1); + } + + { + // x=1, y=1 + std::size_t index = offEndX + offEndY; + std::size_t index0 = 5; + std::size_t index1 = 5; + + double dot = vector3_dot(tangentX[index0], tangentY[index1]); + double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]); + + bestTangents11(nFlagsX, dot, length, index0, index1); + + accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1); + } + + //normalise normals that won't be accumulated again + if (i != 0 || j != 0) { + normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offStartY)); + normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offStartY)); + normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offStartY)); + } + if (i + 3 == m_width) { + normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offStartY)); + normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offStartY)); + normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offStartY)); + } + if (j + 3 == m_height) { + normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offEndY)); + normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offEndY)); + normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offEndY)); + } + if (i + 3 == m_width && j + 3 == m_height) { + normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offEndY)); + normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offEndY)); + normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offEndY)); + } + + // set flags to average normals between shared edges + if (j != 0) { + nFlagsX |= AVERAGE; + } + if (i != 0) { + nFlagsY |= AVERAGE; + } + // set flags to save evaluating shared edges twice + nFlagsX |= SPLIT; + nFlagsY |= SPLIT; + + // if the patch is curved.. tesselate recursively + // use the relevant control curves for this sub-patch + if (m_patchDef3) { + TesselateSubMatrixFixed(m_tess.m_vertices.data() + offStartX + offStartY, 1, m_tess.m_nArrayWidth, + nFlagsX, nFlagsY, subMatrix); + } else { + if (!leafX) { + TesselateSubMatrix(m_tess.m_curveTreeU[i >> 1], m_tess.m_curveTreeV[j >> 1], + offStartX, offStartY, offEndX, offEndY, // array offsets + nFlagsX, nFlagsY, + subMatrix[1][0]->m_vertex, subMatrix[1][1]->m_vertex, + subMatrix[1][2]->m_vertex, + subMatrix[1][0]->m_texcoord, subMatrix[1][1]->m_texcoord, + subMatrix[1][2]->m_texcoord, + false); + } else if (!leafY) { + TesselateSubMatrix(m_tess.m_curveTreeV[j >> 1], m_tess.m_curveTreeU[i >> 1], + offStartY, offStartX, offEndY, offEndX, // array offsets + nFlagsY, nFlagsX, + subMatrix[0][1]->m_vertex, subMatrix[1][1]->m_vertex, + subMatrix[2][1]->m_vertex, + subMatrix[0][1]->m_texcoord, subMatrix[1][1]->m_texcoord, + subMatrix[2][1]->m_texcoord, + true); + } + } + + offStartX = offEndX; + } + offStartY = offEndY; + } + } +} + + +class PatchFilterWrapper : public Filter { + bool m_active; + bool m_invert; + PatchFilter &m_filter; public: -PatchFilterWrapper( PatchFilter& filter, bool invert ) : m_invert( invert ), m_filter( filter ){ -} -void setActive( bool active ){ - m_active = active; -} -bool active(){ - return m_active; -} -bool filter( const Patch& patch ){ - return m_invert ^ m_filter.filter( patch ); -} + PatchFilterWrapper(PatchFilter &filter, bool invert) : m_invert(invert), m_filter(filter) + { + } + + void setActive(bool active) + { + m_active = active; + } + + bool active() + { + return m_active; + } + + bool filter(const Patch &patch) + { + return m_invert ^ m_filter.filter(patch); + } }; typedef std::list PatchFilters; PatchFilters g_patchFilters; -void add_patch_filter( PatchFilter& filter, int mask, bool invert ){ - g_patchFilters.push_back( PatchFilterWrapper( filter, invert ) ); - GlobalFilterSystem().addFilter( g_patchFilters.back(), mask ); +void add_patch_filter(PatchFilter &filter, int mask, bool invert) +{ + g_patchFilters.push_back(PatchFilterWrapper(filter, invert)); + GlobalFilterSystem().addFilter(g_patchFilters.back(), mask); } -bool patch_filtered( Patch& patch ){ - for ( PatchFilters::iterator i = g_patchFilters.begin(); i != g_patchFilters.end(); ++i ) - { - if ( ( *i ).active() && ( *i ).filter( patch ) ) { - return true; - } - } - return false; +bool patch_filtered(Patch &patch) +{ + for (PatchFilters::iterator i = g_patchFilters.begin(); i != g_patchFilters.end(); ++i) { + if ((*i).active() && (*i).filter(patch)) { + return true; + } + } + return false; }