X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fpatch.cpp;h=f4bc0b2a873494012b9732d62ae01b485f1da808;hb=37787ff58d17054395ece7e19db0bd07dde08fc6;hp=a9e452d91655ae90d677eb1bba04354272e36c87;hpb=d9e57a87b9d157ffe13d93f33c9570592c9fe506;p=xonotic%2Fnetradiant.git diff --git a/radiant/patch.cpp b/radiant/patch.cpp index a9e452d9..f4bc0b2a 100644 --- a/radiant/patch.cpp +++ b/radiant/patch.cpp @@ -1,27 +1,27 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "patch.h" -#include +#include #include "preferences.h" #include "brush_primit.h" #include "signal/signal.h" @@ -29,20 +29,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Signal0 g_patchTextureChangedCallbacks; -void Patch_addTextureChangedCallback(const SignalHandler& handler) +void Patch_addTextureChangedCallback(const SignalHandler &handler) { - g_patchTextureChangedCallbacks.connectLast(handler); + g_patchTextureChangedCallbacks.connectLast(handler); } void Patch_textureChanged() { - g_patchTextureChangedCallbacks(); + 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; @@ -53,684 +53,652 @@ int g_PatchSubdivideThreshold = 4; void BezierCurveTree_Delete(BezierCurveTree *pCurve) { - if(pCurve) - { - BezierCurveTree_Delete(pCurve->left); - BezierCurveTree_Delete(pCurve->right); - delete 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; + 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)); + 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 v3(vTemp); - const double width = vector3_length(v3); - vector3_scale(v3, 1.0 / width); + vector3_normalise(v1); + vector3_normalise(v2); + if (vector3_equal(v1, v2)) { + return false; + } - if(vector3_equal(v1, v3) && vector3_equal(v2, v3)) - return false; - - const double angle = acos(vector3_dot(v1, v2)) / c_pi; + 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; + } - const double index = width * angle; + const double angle = acos(vector3_dot(v1, v2)) / c_pi; - if(index > static_cast(g_PatchSubdivideThreshold)) - return true; - return false; + const double index = width * angle; + + 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); + 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; + 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); + } } - for(GSList* l = pRightList; l != 0; l = g_slist_next(l)) - { - delete (BezierCurve*)l->data; + 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; } - - 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) +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; + 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; + 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()); - } + 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) +inline const Colour4b &colour_for_index(std::size_t i, std::size_t width) { - return (i%2 || (i/width)%2) ? colour_inside : colour_corner; + return (i % 2 || (i / width) % 2) ? colour_inside : colour_corner; } inline bool float_valid(float f) { - return f == 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; + 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; + 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))))); + 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::iterator last = first + m_tess.m_lenStrips; - - for(Array::iterator i(first); i+2 != last; i += 2) - { - ArbitraryMeshTriangle_sumTangents(m_tess.m_vertices[*(i+0)], m_tess.m_vertices[*(i+1)], m_tess.m_vertices[*(i+2)]); - ArbitraryMeshTriangle_sumTangents(m_tess.m_vertices[*(i+2)], m_tess.m_vertices[*(i+1)], m_tess.m_vertices[*(i+3)]); - } - - first = last; + 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); + } + } } - for(Array::iterator i = m_tess.m_vertices.begin(); i != m_tess.m_vertices.end(); ++i) - { - vector3_normalise(reinterpret_cast((*i).tangent)); - vector3_normalise(reinterpret_cast((*i).bitangent)); - } - } +#if 0 + { + Array::iterator first = m_tess.m_indices.begin(); + for ( std::size_t s = 0; s < m_tess.m_numStrips; s++ ) + { + Array::iterator last = first + m_tess.m_lenStrips; + + for ( Array::iterator i( first ); i + 2 != last; i += 2 ) + { + ArbitraryMeshTriangle_sumTangents( m_tess.m_vertices[*( i + 0 )], m_tess.m_vertices[*( i + 1 )], m_tess.m_vertices[*( i + 2 )] ); + ArbitraryMeshTriangle_sumTangents( m_tess.m_vertices[*( i + 2 )], m_tess.m_vertices[*( i + 1 )], m_tess.m_vertices[*( i + 3 )] ); + } + + first = last; + } + + for ( Array::iterator i = m_tess.m_vertices.begin(); i != m_tess.m_vertices.end(); ++i ) + { + vector3_normalise( reinterpret_cast( ( *i ).tangent ) ); + vector3_normalise( reinterpret_cast( ( *i ).bitangent ) ); + } + } #endif - SceneChangeNotify(); + SceneChangeNotify(); } void Patch::InvertMatrix() { - undoSave(); + undoSave(); - PatchControlArray_invert(m_ctrl, m_width, m_height); + PatchControlArray_invert(m_ctrl, m_width, m_height); - controlPointsChanged(); + controlPointsChanged(); } void Patch::TransposeMatrix() { - undoSave(); + undoSave(); + + { + Array tmp(m_width * m_height); + copy_ctrl(tmp.data(), m_ctrl.data(), m_ctrl.data() + m_width * m_height); - { - 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; + } + } + } - 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; } - } - { - std::size_t tmp = m_width; - m_width = m_height; - m_height = tmp; - } - - controlPointsChanged(); + 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;hm_vertex = vector3_mid(p1->m_vertex, p3->m_vertex); - p1 = p3; + 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(); + + 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;hm_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; - } - } + std::size_t w, h, width, height, row_stride, col_stride; + bool wrap; + PatchControl *p1, *p2, *p3, *p2b; - for(h=0;hm_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(); + 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= MIN_PATCH_WIDTH)) { + RemovePoints(COL, bFirst); + } else if (m_height - 2 >= MIN_PATCH_HEIGHT) { + RemovePoints(ROW, bFirst); + } } - } - else - { - for (i=0; i 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; + patch->ConstructSeam(eType, p.data(), width); + return patch; } void Patch::FlipTexture(int nAxis) { - undoSave(); + undoSave(); - for(PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) - { - (*i).m_texcoord[nAxis] = -(*i).m_texcoord[nAxis]; - } - - controlPointsChanged(); + for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) { + (*i).m_texcoord[nAxis] = -(*i).m_texcoord[nAxis]; + } + + controlPointsChanged(); } void Patch::TranslateTexture(float s, float t) { - undoSave(); + 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(); + 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(); + undoSave(); - 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); - } + const float s = static_cast( sin(degrees_to_radians(angle))); + const float c = static_cast( cos(degrees_to_radians(angle))); - controlPointsChanged(); + 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(); } void Patch::SetTextureRepeat(float s, float t) { - std::size_t w, h; - float si, ti, sc, tc; - PatchControl *pDest; - - undoSave(); + std::size_t w, h; + float si, ti, sc, tc; + PatchControl *pDest; - si = s / (float)(m_width - 1); - ti = t / (float)(m_height - 1); + undoSave(); - pDest = m_ctrl.data(); - for (h=0, tc = 0.0f; hm_texcoord[0] = sc; - pDest->m_texcoord[1] = tc; - pDest++; + 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++; + } } - } - controlPointsChanged(); + controlPointsChanged(); } /* -void Patch::SetTextureInfo(texdef_t *pt) -{ - if(pt->getShift()[0] || pt->getShift()[1]) + void Patch::SetTextureInfo(texdef_t *pt) + { + if(pt->getShift()[0] || pt->getShift()[1]) TranslateTexture (pt->getShift()[0], pt->getShift()[1]); - else if(pt->getScale()[0] || pt->getScale()[1]) - { + else if(pt->getScale()[0] || pt->getScale()[1]) + { if(pt->getScale()[0] == 0.0f) pt->setScale(0, 1.0f); if(pt->getScale()[1] == 0.0f) pt->setScale(1, 1.0f); ScaleTexture (pt->getScale()[0], pt->getScale()[1]); - } - else if(pt->rotate) + } + else if(pt->rotate) RotateTexture (pt->rotate); -} -*/ + } + */ -inline int texture_axis(const Vector3& normal) +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; + // 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]; + 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 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 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_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)); + ProjectTexture(texture_axis(normal)); } // uses longest parallel chord to calculate texture coords for each row/col void Patch::NaturalTexture() { - undoSave(); + 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; wm_texcoord[0] = static_cast(tex); - } - - if(w+1 == m_width) - break; - - { - PatchControl* pHeight = pWidth; - for (std::size_t h=0; hm_vertex, (pHeight+1)->m_vertex)); - double length = tex + (vector3_length(v) / fSize); - if(fabs(length) > texBest) texBest = length; - } - } + float fSize = (float) m_state->getTexture().width * Texdef_getDefaultTextureScale(); - tex=texBest; - } - } + 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 ); + } + } - { - float fSize = -(float)m_state->getTexture().height * Texdef_getDefaultTextureScale(); + if (w + 1 == m_width) { + break; + } - double texBest = 0; - double tex = 0; - PatchControl* pHeight = m_ctrl.data(); - for (std::size_t h=0; hm_texcoord[1] = static_cast(tex); - } - - if(h+1 == m_height) - break; - - { - PatchControl* pWidth = pHeight; - for (std::size_t w=0; wm_vertex, (pWidth+m_width)->m_vertex)); - double length = tex + (vector3_length(v) / fSize); - if(fabs(length) > texBest) texBest = length; + { + 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; + tex = texBest; + } } - } - controlPointsChanged(); + controlPointsChanged(); } @@ -739,2158 +707,2052 @@ void Patch::NaturalTexture() void Patch::AccumulateBBox() { - m_aabb_local = AABB(); + 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(); + 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; - } - - 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; + 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; - } - } - 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; + 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(); + PatchInstance* patch = Instance_getPatch(instance); + 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; + } + } + + { + 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; + } + } } - 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(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]); + Array tmp(m_ctrl); - p2->m_vertex[i] = float_mid(r2a->m_vertex[i], r2b->m_vertex[i]); + 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; } - for(std::size_t i = 0; i != 2; ++i) - { - r2a->m_texcoord[i] = float_mid(c2b->m_texcoord[i], p1->m_texcoord[i]); + 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; + } - r2b->m_texcoord[i] = float_mid(c2a->m_texcoord[i], c2b->m_texcoord[i]); + p1 = tmp.data() + (w * col_stride + pos * row_stride); + p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2); - p2->m_texcoord[i] = float_mid(r2a->m_texcoord[i], r2b->m_texcoord[i]); + 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; + 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; - } - } - 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; + case COL: + col_stride = m_width; + row_stride = 1; + width = m_height; + height = m_width; 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(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; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; } - 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++) + std::size_t pos = 0; { - (p2-row_stride2)->m_vertex[i] = ((p1+2*row_stride)->m_vertex[i]+(p1-2*row_stride)->m_vertex[i]) * 0.5f; + 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; + } + } - (p2-row_stride2)->m_vertex[i] = (p2-row_stride2)->m_vertex[i]+(2.0f * ((p1)->m_vertex[i]-(p2-row_stride2)->m_vertex[i])); + { + 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; + } + } + } } - 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])); - } - } -} + Array tmp(m_ctrl); -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; + 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; + } - bool degenerate = (mid % 2) != 0; + p1 = tmp.data() + (w * col_stride + pos * row_stride); + p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2); - std::size_t newHeight = mid + (degenerate ? 2 : 1); + 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; - setDims(3, newHeight); - - if(degenerate) - { - ++mid; - for(std::size_t i = width; i != width + 2; ++i) - { - p[i] = p[width - 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; - { - 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)]; + (p2 - row_stride2)->m_texcoord[i] = (p2 - row_stride2)->m_texcoord[i] + + (2.0f * ((p1)->m_texcoord[i] - (p2 - row_stride2)->m_texcoord[i])); } - } - - Redisperse(COL); } - break; - default: - ERROR_MESSAGE("invalid patch-cap type"); - return; - } - CapTexture(); - controlPointsChanged(); } -void Patch::ProjectTexture(int nAxis) +void Patch::ConstructSeam(EPatchCap eType, Vector3 *p, std::size_t width) { - 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; hm_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; + 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]; } - } - { - 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; + 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]; } - } - { - 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 == 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, - }; + 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; - setDims(5, 3); + bool degenerate = (mid % 2) != 0; - 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]; - } - } - } + std::size_t newHeight = mid + (degenerate ? 2 : 1); - if(eType == eDenseCylinder) - { - InsertRemove(true, false, true); - } + setDims(3, newHeight); - if(eType == eVeryDenseCylinder) - { - InsertRemove(true, false, false); - InsertRemove(true, false, true); - } + if (degenerate) { + ++mid; + for (std::size_t i = width; i != width + 2; ++i) { + p[i] = p[width - 1]; + } + } - NaturalTexture(); -} + { + 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)]; + } + } -void Patch::RenderDebug(RenderStateFlags state) const -{ - for (std::size_t i = 0; inormal)); - 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)); + Redisperse(COL); + } + break; + default: + ERROR_MESSAGE("invalid patch-cap type"); + return; } - glEnd(); - } + CapTexture(); + controlPointsChanged(); } -void RenderablePatchSolid::RenderNormals() const +void Patch::ProjectTexture(int nAxis) { - 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;ivertex), - 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 + undoSave(); + int s, t; -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; + 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); - 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; + 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; + } - 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; + 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; + } - 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; + 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; + } - return nDegen; + 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; + -inline void deCasteljau3(const Vector3& P0, const Vector3& P1, const Vector3& P2, Vector3& P01, Vector3& P12, Vector3& P012) +unsigned int subarray_get_degen(PatchControlIter subarray, std::size_t strideU, std::size_t strideV) { - P01 = vector3_mid(P0, P1); - P12 = vector3_mid(P1, P2); - P012 = vector3_mid(P01, P12); + 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 ) +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); + 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 ) +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]); + 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) +inline Vector2 &texcoord_for_index(Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].texcoord); + return reinterpret_cast( vertices[index].texcoord ); } -inline Vector3& vertex_for_index(Array& vertices, std::size_t index) +inline Vector3 &vertex_for_index(Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].vertex); + return reinterpret_cast( vertices[index].vertex ); } -inline Vector3& normal_for_index(Array& vertices, std::size_t index) +inline Vector3 &normal_for_index(Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].normal); + return reinterpret_cast( vertices[index].normal ); } -inline Vector3& tangent_for_index(Array& vertices, std::size_t index) +inline Vector3 &tangent_for_index(Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].tangent); + return reinterpret_cast( vertices[index].tangent ); } -inline Vector3& bitangent_for_index(Array& vertices, std::size_t index) +inline Vector3 &bitangent_for_index(Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].bitangent); + return reinterpret_cast( vertices[index].bitangent ); } -inline const Vector2& texcoord_for_index(const Array& vertices, std::size_t index) +inline const Vector2 &texcoord_for_index(const Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].texcoord); + return reinterpret_cast( vertices[index].texcoord ); } -inline const Vector3& vertex_for_index(const Array& vertices, std::size_t index) +inline const Vector3 &vertex_for_index(const Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].vertex); + return reinterpret_cast( vertices[index].vertex ); } -inline const Vector3& normal_for_index(const Array& vertices, std::size_t index) +inline const Vector3 &normal_for_index(const Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].normal); + return reinterpret_cast( vertices[index].normal ); } -inline const Vector3& tangent_for_index(const Array& vertices, std::size_t index) +inline const Vector3 &tangent_for_index(const Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].tangent); + return reinterpret_cast( vertices[index].tangent ); } -inline const Vector3& bitangent_for_index(const Array& vertices, std::size_t index) +inline const Vector3 &bitangent_for_index(const Array &vertices, std::size_t index) { - return reinterpret_cast(vertices[index].bitangent); + return reinterpret_cast( vertices[index].bitangent ); } #include "math/curve.h" -inline PatchControl QuadraticBezier_evaluate(const PatchControl* firstPoint, double t) +inline PatchControl QuadraticBezier_evaluate(const PatchControl *firstPoint, double t) { - PatchControl result = { Vector3(0, 0, 0), Vector2(0, 0) }; - double denominator = 0; + 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; + } - { - 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; +} - 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 Vector3 vector3_linear_interpolated(const Vector3& a, const Vector3& b, double t) +inline Vector2 vector2_linear_interpolated(const Vector2 &a, const Vector2 &b, double t) { - return vector3_added(vector3_scaled(a, 1.0 - t), vector3_scaled(b, t)); + return vector2_added(vector2_scaled(a, 1.0 - t), vector2_scaled(b, t)); } -inline Vector2 vector2_linear_interpolated(const Vector2& a, const Vector2& b, double t) +void normalise_safe(Vector3 &normal) { - return vector2_added(vector2_scaled(a, 1.0 - t), vector2_scaled(b, t)); + if (!vector3_equal(normal, g_vector3_identity)) { + vector3_normalise(normal); + } } -void normalise_safe(Vector3& normal) +inline void QuadraticBezier_evaluate(const PatchControl &a, const PatchControl &b, const PatchControl &c, double t, + PatchControl &point, PatchControl &left, PatchControl &right) { - if(!vector3_equal(normal, g_vector3_identity)) - { - vector3_normalise(normal); - } + 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); } -inline void QuadraticBezier_evaluate(const PatchControl& a, const PatchControl& b, const PatchControl& c, double t, PatchControl& point, PatchControl& left, PatchControl& right) +void Patch::TesselateSubMatrixFixed(ArbitraryMeshVertex *vertices, std::size_t strideX, std::size_t strideY, + unsigned int nFlagsX, unsigned int nFlagsY, PatchControl *subMatrix[3][3]) { - 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); + 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::TesselateSubMatrixFixed(ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3]) +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) { - 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; + int newFlagsX, newFlagsY; - 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]); + 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; - 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; + // texcoords - ArbitraryMeshVertex a, b, c; + 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)); - 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); + 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; } - 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)); + 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; + } } - else - { - normal3f_to_vector3(p->normal) = normal; - normal3f_to_vector3(p->tangent) = tangent; - normal3f_to_vector3(p->bitangent) = bitangent; + 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; + } } - } - 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; + // verts - 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; + 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)); - { - // 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) ); + 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)); - 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) ); + tmp = mid; - texTmp = texMid; + BezierInterpolate3(left, + vertex_1_0, + tmp, + vertex_1_1, + right); - BezierInterpolate2(texLeft, - texcoord_1_0, - texTmp, - texcoord_1_1, - texRight); + if (!BezierCurveTree_isLeaf(BY)) { + vertex_for_index(m_tess.m_vertices, BX->index + BY->index) = tmp; + } - 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(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)) - { - 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)) { + 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)) - { - texcoord_for_index(m_tess.m_vertices, BX->right->index + BY->index) = texcoord_1_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); + } - // verts + Vector3 tangentV; - 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) ); + 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; + } - 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) ); + 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; + } + } - tmp = mid; + { + 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); + } - BezierInterpolate3( left, - vertex_1_0, - tmp, - vertex_1_1, - right ); + Vector3 tangentV; - if(!BezierCurveTree_isLeaf(BY)) - { - vertex_for_index(m_tess.m_vertices, BX->index + BY->index) = tmp; - } + 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; + } - - 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; + 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(!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 (bTranspose) { + p = vector3_cross(tangentV, tangentU); + } else { + p = vector3_cross(tangentU, tangentV); + } + normalise_safe(p); - if(!BezierCurveTree_isLeaf(BY)) - { - vertex_for_index(m_tess.m_vertices, BX->right->index + BY->index) = vertex_1_1; - } + ArbitraryMeshTriangle_calcTangents(a, b, c, ps, pt); + normalise_safe(ps); + normalise_safe(pt); + } } - // 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; + newFlagsX = newFlagsY = 0; - if((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_0b)) - { + 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 |= (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 ); + newFlagsY |= DEGEN_1b; + newFlagsY |= DEGEN_2b; } - 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 ); + + //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); - } + 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; + 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); + } - if(!m_patchDef3) - { - BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV); + break; + default: + ERROR_MESSAGE("neither row-major nor column-major"); + return; } - break; - default: - ERROR_MESSAGE("neither row-major nor column-major"); - return; - } - - Array arrayLength(length); - Array pCurveTree(length); + Array arrayLength(length); + Array pCurveTree(length); - std::size_t nArrayLength = 1; + 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 (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; + } - if(j+2 >= cross) - { - break; + 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]; } - - // 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); + 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; } - break; - } } -inline void vertex_assign_ctrl(ArbitraryMeshVertex& vertex, const PatchControl& ctrl) +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); + vertex.vertex = vertex3f_for_vector3(ctrl.m_vertex); + vertex.texcoord = texcoord2f_for_vector2(ctrl.m_texcoord); } -inline void vertex_clear_normal(ArbitraryMeshVertex& vertex) +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); + 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; + 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) +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; + 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) + +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; + 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) +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; + 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) +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)); + 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)); + } } - if(!vector3_equal(t, g_vector3_identity)) + { - vector3_add(bitangent_for_index(m_tess.m_vertices, index), vector3_normalised(t)); + 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 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 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 + 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)); + // 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>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]); + // set up strip indices + if (bWidthStrips) { + m_tess.m_numStrips = m_tess.m_nArrayHeight - 1; + m_tess.m_lenStrips = m_tess.m_nArrayWidth * 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]); + 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); } - } - } - - // 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; + } 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); - 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)); + { + 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; } + } +} - // 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 = false; + 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; + } -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); - } + 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) +void add_patch_filter(PatchFilter &filter, int mask, bool invert) { - g_patchFilters.push_back(PatchFilterWrapper(filter, invert)); - GlobalFilterSystem().addFilter(g_patchFilters.back(), mask); + g_patchFilters.push_back(PatchFilterWrapper(filter, invert)); + GlobalFilterSystem().addFilter(g_patchFilters.back(), mask); } -bool patch_filtered(Patch& patch) +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; + for (PatchFilters::iterator i = g_patchFilters.begin(); i != g_patchFilters.end(); ++i) { + if ((*i).active() && (*i).filter(patch)) { + return true; + } } - } - return false; + return false; }