2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "preferences.h"
26 #include "brush_primit.h"
27 #include "signal/signal.h"
30 Signal0 g_patchTextureChangedCallbacks;
32 void Patch_addTextureChangedCallback(const SignalHandler &handler)
34 g_patchTextureChangedCallbacks.connectLast(handler);
37 void Patch_textureChanged()
39 g_patchTextureChangedCallbacks();
43 Shader *PatchInstance::m_state_selpoint;
44 Shader *Patch::m_state_ctrl;
45 Shader *Patch::m_state_lattice;
46 EPatchType Patch::m_type;
49 std::size_t MAX_PATCH_WIDTH = 0;
50 std::size_t MAX_PATCH_HEIGHT = 0;
52 int g_PatchSubdivideThreshold = 4;
54 void BezierCurveTree_Delete(BezierCurveTree *pCurve)
57 BezierCurveTree_Delete(pCurve->left);
58 BezierCurveTree_Delete(pCurve->right);
63 std::size_t BezierCurveTree_Setup(BezierCurveTree *pCurve, std::size_t index, std::size_t stride)
66 if (pCurve->left && pCurve->right) {
67 index = BezierCurveTree_Setup(pCurve->left, index, stride);
68 pCurve->index = index * stride;
70 index = BezierCurveTree_Setup(pCurve->right, index, stride);
72 pCurve->index = BEZIERCURVETREE_MAX_INDEX;
79 bool BezierCurve_IsCurved(BezierCurve *pCurve)
81 Vector3 vTemp(vector3_subtracted(pCurve->right, pCurve->left));
82 Vector3 v1(vector3_subtracted(pCurve->crd, pCurve->left));
83 Vector3 v2(vector3_subtracted(pCurve->right, pCurve->crd));
85 if (vector3_equal(v1, g_vector3_identity) || vector3_equal(vTemp, v1)) { // return 0 if 1->2 == 0 or 1->2 == 1->3
89 vector3_normalise(v1);
90 vector3_normalise(v2);
91 if (vector3_equal(v1, v2)) {
96 const double width = vector3_length(v3);
97 vector3_scale(v3, 1.0 / width);
99 if (vector3_equal(v1, v3) && vector3_equal(v2, v3)) {
103 const double angle = acos(vector3_dot(v1, v2)) / c_pi;
105 const double index = width * angle;
107 if (index > static_cast<double>( g_PatchSubdivideThreshold )) {
113 void BezierInterpolate(BezierCurve *pCurve)
115 pCurve->left = vector3_mid(pCurve->left, pCurve->crd);
116 pCurve->right = vector3_mid(pCurve->crd, pCurve->right);
117 pCurve->crd = vector3_mid(pCurve->left, pCurve->right);
120 const std::size_t PATCH_MAX_SUBDIVISION_DEPTH = 16;
122 void BezierCurveTree_FromCurveList(BezierCurveTree *pTree, GSList *pCurveList, std::size_t depth = 0)
124 GSList *pLeftList = 0;
125 GSList *pRightList = 0;
126 BezierCurve *pCurve, *pLeftCurve, *pRightCurve;
129 for (GSList *l = pCurveList; l; l = l->next) {
130 pCurve = (BezierCurve *) (l->data);
131 if (bSplit || BezierCurve_IsCurved(pCurve)) {
133 pLeftCurve = new BezierCurve;
134 pRightCurve = new BezierCurve;
135 pLeftCurve->left = pCurve->left;
136 pRightCurve->right = pCurve->right;
137 BezierInterpolate(pCurve);
138 pLeftCurve->crd = pCurve->left;
139 pRightCurve->crd = pCurve->right;
140 pLeftCurve->right = pCurve->crd;
141 pRightCurve->left = pCurve->crd;
143 pLeftList = g_slist_prepend(pLeftList, pLeftCurve);
144 pRightList = g_slist_prepend(pRightList, pRightCurve);
148 if (pLeftList != 0 && pRightList != 0 && depth != PATCH_MAX_SUBDIVISION_DEPTH) {
149 pTree->left = new BezierCurveTree;
150 pTree->right = new BezierCurveTree;
151 BezierCurveTree_FromCurveList(pTree->left, pLeftList, depth + 1);
152 BezierCurveTree_FromCurveList(pTree->right, pRightList, depth + 1);
154 for (GSList *l = pLeftList; l != 0; l = g_slist_next(l)) {
155 delete (BezierCurve *) l->data;
158 for (GSList *l = pRightList; l != 0; l = g_slist_next(l)) {
159 delete (BezierCurve *) l->data;
162 g_slist_free(pLeftList);
163 g_slist_free(pRightList);
171 int Patch::m_CycleCapIndex = 0;
174 void Patch::setDims(std::size_t w, std::size_t h)
179 ASSERT_MESSAGE(w <= MAX_PATCH_WIDTH, "patch too wide");
180 if (w > MAX_PATCH_WIDTH) {
182 } else if (w < MIN_PATCH_WIDTH) {
189 ASSERT_MESSAGE(h <= MAX_PATCH_HEIGHT, "patch too tall");
190 if (h > MAX_PATCH_HEIGHT) {
191 h = MAX_PATCH_HEIGHT;
192 } else if (h < MIN_PATCH_HEIGHT) {
193 h = MIN_PATCH_HEIGHT;
199 if (m_width * m_height != m_ctrl.size()) {
200 m_ctrl.resize(m_width * m_height);
201 onAllocate(m_ctrl.size());
205 inline const Colour4b &colour_for_index(std::size_t i, std::size_t width)
207 return (i % 2 || (i / width) % 2) ? colour_inside : colour_corner;
210 inline bool float_valid(float f)
215 bool Patch::isValid() const
217 if (!m_width || !m_height) {
221 for (const_iterator i = m_ctrl.begin(); i != m_ctrl.end(); ++i) {
222 if (!float_valid((*i).m_vertex.x())
223 || !float_valid((*i).m_vertex.y())
224 || !float_valid((*i).m_vertex.z())
225 || !float_valid((*i).m_texcoord.x())
226 || !float_valid((*i).m_texcoord.y())) {
227 globalErrorStream() << "patch has invalid control points\n";
234 void Patch::UpdateCachedData()
236 m_ctrl_vertices.clear();
237 m_lattice_indices.clear();
240 m_tess.m_numStrips = 0;
241 m_tess.m_lenStrips = 0;
242 m_tess.m_nArrayHeight = 0;
243 m_tess.m_nArrayWidth = 0;
244 m_tess.m_curveTreeU.resize(0);
245 m_tess.m_curveTreeV.resize(0);
246 m_tess.m_indices.resize(0);
247 m_tess.m_vertices.resize(0);
248 m_tess.m_arrayHeight.resize(0);
249 m_tess.m_arrayWidth.resize(0);
250 m_aabb_local = AABB();
254 BuildTesselationCurves(ROW);
255 BuildTesselationCurves(COL);
259 IndexBuffer ctrl_indices;
261 m_lattice_indices.reserve(((m_width * (m_height - 1)) + (m_height * (m_width - 1))) << 1);
262 ctrl_indices.reserve(m_ctrlTransformed.size());
264 UniqueVertexBuffer<PointVertex> inserter(m_ctrl_vertices);
265 for (iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i) {
266 ctrl_indices.insert(inserter.insert(pointvertex_quantised(
267 PointVertex(reinterpret_cast<const Vertex3f &>((*i).m_vertex ),
268 colour_for_index(i - m_ctrlTransformed.begin(), m_width)))));
272 for (IndexBuffer::iterator i = ctrl_indices.begin(); i != ctrl_indices.end(); ++i) {
273 if (std::size_t(i - ctrl_indices.begin()) % m_width) {
274 m_lattice_indices.insert(*(i - 1));
275 m_lattice_indices.insert(*i);
277 if (std::size_t(i - ctrl_indices.begin()) >= m_width) {
278 m_lattice_indices.insert(*(i - m_width));
279 m_lattice_indices.insert(*i);
286 Array<RenderIndex>::iterator first = m_tess.m_indices.begin();
287 for ( std::size_t s = 0; s < m_tess.m_numStrips; s++ )
289 Array<RenderIndex>::iterator last = first + m_tess.m_lenStrips;
291 for ( Array<RenderIndex>::iterator i( first ); i + 2 != last; i += 2 )
293 ArbitraryMeshTriangle_sumTangents( m_tess.m_vertices[*( i + 0 )], m_tess.m_vertices[*( i + 1 )], m_tess.m_vertices[*( i + 2 )] );
294 ArbitraryMeshTriangle_sumTangents( m_tess.m_vertices[*( i + 2 )], m_tess.m_vertices[*( i + 1 )], m_tess.m_vertices[*( i + 3 )] );
300 for ( Array<ArbitraryMeshVertex>::iterator i = m_tess.m_vertices.begin(); i != m_tess.m_vertices.end(); ++i )
302 vector3_normalise( reinterpret_cast<Vector3&>( ( *i ).tangent ) );
303 vector3_normalise( reinterpret_cast<Vector3&>( ( *i ).bitangent ) );
311 void Patch::InvertMatrix()
315 PatchControlArray_invert(m_ctrl, m_width, m_height);
317 controlPointsChanged();
320 void Patch::TransposeMatrix()
325 Array<PatchControl> tmp(m_width * m_height);
326 copy_ctrl(tmp.data(), m_ctrl.data(), m_ctrl.data() + m_width * m_height);
328 PatchControlIter from = tmp.data();
329 for (std::size_t h = 0; h != m_height; ++h) {
330 PatchControlIter to = m_ctrl.data() + h;
331 for (std::size_t w = 0; w != m_width; ++w, ++from, to += m_height) {
338 std::size_t tmp = m_width;
343 controlPointsChanged();
346 void Patch::Redisperse(EMatrixMajor mt)
348 std::size_t w, h, width, height, row_stride, col_stride;
349 PatchControl *p1, *p2, *p3;
355 width = (m_width - 1) >> 1;
358 row_stride = m_width;
361 width = (m_height - 1) >> 1;
363 col_stride = m_width;
367 ERROR_MESSAGE("neither row-major nor column-major");
371 for (h = 0; h < height; h++) {
372 p1 = m_ctrl.data() + (h * row_stride);
373 for (w = 0; w < width; w++) {
374 p2 = p1 + col_stride;
375 p3 = p2 + col_stride;
376 p2->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex);
381 controlPointsChanged();
384 void Patch::Smooth(EMatrixMajor mt)
386 std::size_t w, h, width, height, row_stride, col_stride;
388 PatchControl *p1, *p2, *p3, *p2b;
394 width = (m_width - 1) >> 1;
397 row_stride = m_width;
400 width = (m_height - 1) >> 1;
402 col_stride = m_width;
406 ERROR_MESSAGE("neither row-major nor column-major");
411 for (h = 0; h < height; h++) {
412 p1 = m_ctrl.data() + (h * row_stride);
413 p2 = p1 + (2 * width) * col_stride;
414 //globalErrorStream() << "compare " << p1->m_vertex << " and " << p2->m_vertex << "\n";
415 if (vector3_length_squared(vector3_subtracted(p1->m_vertex, p2->m_vertex)) > 1.0) {
416 //globalErrorStream() << "too far\n";
422 for (h = 0; h < height; h++) {
423 p1 = m_ctrl.data() + (h * row_stride) + col_stride;
424 for (w = 0; w < width - 1; w++) {
425 p2 = p1 + col_stride;
426 p3 = p2 + col_stride;
427 p2->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex);
431 p1 = m_ctrl.data() + (h * row_stride) + (2 * width - 1) * col_stride;
432 p2 = m_ctrl.data() + (h * row_stride);
433 p2b = m_ctrl.data() + (h * row_stride) + (2 * width) * col_stride;
434 p3 = m_ctrl.data() + (h * row_stride) + col_stride;
435 p2->m_vertex = p2b->m_vertex = vector3_mid(p1->m_vertex, p3->m_vertex);
439 controlPointsChanged();
442 void Patch::InsertRemove(bool bInsert, bool bColumn, bool bFirst)
447 if (bColumn && (m_width + 2 <= MAX_PATCH_WIDTH)) {
448 InsertPoints(COL, bFirst);
449 } else if (m_height + 2 <= MAX_PATCH_HEIGHT) {
450 InsertPoints(ROW, bFirst);
453 if (bColumn && (m_width - 2 >= MIN_PATCH_WIDTH)) {
454 RemovePoints(COL, bFirst);
455 } else if (m_height - 2 >= MIN_PATCH_HEIGHT) {
456 RemovePoints(ROW, bFirst);
460 controlPointsChanged();
463 Patch *Patch::MakeCap(Patch *patch, EPatchCap eType, EMatrixMajor mt, bool bFirst)
465 std::size_t i, width, height;
477 ERROR_MESSAGE("neither row-major nor column-major");
481 Array<Vector3> p(width);
483 std::size_t nIndex = (bFirst) ? 0 : height - 1;
485 for (i = 0; i < width; i++) {
486 p[(bFirst) ? i : (width - 1) - i] = ctrlAt(nIndex, i).m_vertex;
489 for (i = 0; i < width; i++) {
490 p[(bFirst) ? i : (width - 1) - i] = ctrlAt(i, nIndex).m_vertex;
494 patch->ConstructSeam(eType, p.data(), width);
498 void Patch::FlipTexture(int nAxis)
502 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
503 (*i).m_texcoord[nAxis] = -(*i).m_texcoord[nAxis];
506 controlPointsChanged();
509 void Patch::TranslateTexture(float s, float t)
513 s = -1 * s / m_state->getTexture().width;
514 t = t / m_state->getTexture().height;
516 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
517 (*i).m_texcoord[0] += s;
518 (*i).m_texcoord[1] += t;
521 controlPointsChanged();
524 void Patch::ScaleTexture(float s, float t)
528 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
529 (*i).m_texcoord[0] *= s;
530 (*i).m_texcoord[1] *= t;
533 controlPointsChanged();
536 void Patch::RotateTexture(float angle)
540 const float s = static_cast<float>( sin(degrees_to_radians(angle)));
541 const float c = static_cast<float>( cos(degrees_to_radians(angle)));
543 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
544 const float x = (*i).m_texcoord[0];
545 const float y = (*i).m_texcoord[1];
546 (*i).m_texcoord[0] = (x * c) - (y * s);
547 (*i).m_texcoord[1] = (y * c) + (x * s);
550 controlPointsChanged();
554 void Patch::SetTextureRepeat(float s, float t)
557 float si, ti, sc, tc;
562 si = s / (float) (m_width - 1);
563 ti = t / (float) (m_height - 1);
565 pDest = m_ctrl.data();
566 for (h = 0, tc = 0.0f; h < m_height; h++, tc += ti) {
567 for (w = 0, sc = 0.0f; w < m_width; w++, sc += si) {
568 pDest->m_texcoord[0] = sc;
569 pDest->m_texcoord[1] = tc;
574 controlPointsChanged();
578 void Patch::SetTextureInfo(texdef_t *pt)
580 if(pt->getShift()[0] || pt->getShift()[1])
581 TranslateTexture (pt->getShift()[0], pt->getShift()[1]);
582 else if(pt->getScale()[0] || pt->getScale()[1])
584 if(pt->getScale()[0] == 0.0f) pt->setScale(0, 1.0f);
585 if(pt->getScale()[1] == 0.0f) pt->setScale(1, 1.0f);
586 ScaleTexture (pt->getScale()[0], pt->getScale()[1]);
589 RotateTexture (pt->rotate);
593 inline int texture_axis(const Vector3 &normal)
595 // axis dominance order: Z, X, Y
596 return (normal.x() >= normal.y()) ? (normal.x() > normal.z()) ? 0 : 2 : (normal.y() > normal.z()) ? 1 : 2;
599 void Patch::CapTexture()
601 const PatchControl &p1 = m_ctrl[m_width];
602 const PatchControl &p2 = m_ctrl[m_width * (m_height - 1)];
603 const PatchControl &p3 = m_ctrl[(m_width * m_height) - 1];
606 Vector3 normal(g_vector3_identity);
609 Vector3 tmp(vector3_cross(
610 vector3_subtracted(p2.m_vertex, m_ctrl[0].m_vertex),
611 vector3_subtracted(p3.m_vertex, m_ctrl[0].m_vertex)
613 if (!vector3_equal(tmp, g_vector3_identity)) {
614 vector3_add(normal, tmp);
618 Vector3 tmp(vector3_cross(
619 vector3_subtracted(p1.m_vertex, p3.m_vertex),
620 vector3_subtracted(m_ctrl[0].m_vertex, p3.m_vertex)
622 if (!vector3_equal(tmp, g_vector3_identity)) {
623 vector3_add(normal, tmp);
627 ProjectTexture(texture_axis(normal));
630 // uses longest parallel chord to calculate texture coords for each row/col
631 void Patch::NaturalTexture()
636 float fSize = (float) m_state->getTexture().width * Texdef_getDefaultTextureScale();
640 PatchControl *pWidth = m_ctrl.data();
641 for (std::size_t w = 0; w < m_width; w++, pWidth++) {
643 PatchControl *pHeight = pWidth;
644 for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) {
645 pHeight->m_texcoord[0] = static_cast<float>( tex );
649 if (w + 1 == m_width) {
654 PatchControl *pHeight = pWidth;
655 for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) {
656 Vector3 v(vector3_subtracted(pHeight->m_vertex, (pHeight + 1)->m_vertex));
657 double length = tex + (vector3_length(v) / fSize);
658 if (fabs(length) > texBest) {
669 float fSize = -(float) m_state->getTexture().height * Texdef_getDefaultTextureScale();
673 PatchControl *pHeight = m_ctrl.data();
674 for (std::size_t h = 0; h < m_height; h++, pHeight += m_width) {
676 PatchControl *pWidth = pHeight;
677 for (std::size_t w = 0; w < m_width; w++, pWidth++) {
678 pWidth->m_texcoord[1] = static_cast<float>( tex );
682 if (h + 1 == m_height) {
687 PatchControl *pWidth = pHeight;
688 for (std::size_t w = 0; w < m_width; w++, pWidth++) {
689 Vector3 v(vector3_subtracted(pWidth->m_vertex, (pWidth + m_width)->m_vertex));
690 double length = tex + (vector3_length(v) / fSize);
691 if (fabs(length) > texBest) {
701 controlPointsChanged();
708 void Patch::AccumulateBBox()
710 m_aabb_local = AABB();
712 for (PatchControlArray::iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i) {
713 aabb_extend_by_point_safe(m_aabb_local, (*i).m_vertex);
720 void Patch::InsertPoints(EMatrixMajor mt, bool bFirst)
722 std::size_t width, height, row_stride, col_stride;
727 row_stride = m_width;
732 col_stride = m_width;
738 ERROR_MESSAGE("neither row-major nor column-major");
744 PatchControl *p1 = m_ctrl.data();
746 if(GlobalSelectionSystem().countSelected() != 0)
748 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
749 PatchInstance* patch = Instance_getPatch(instance);
750 patch->m_selectable.isSelected();
753 for (std::size_t w = 0; w != width; ++w, p1 += col_stride) {
755 PatchControl *p2 = p1;
756 for (std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride) {
757 if (0) { //p2->m_selectable.isSelected())
768 PatchControl *p2 = p1;
769 for (std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride) {
770 if (0) { //p2->m_selectable.isSelected())
782 Array<PatchControl> tmp(m_ctrl);
784 std::size_t row_stride2, col_stride2;
787 setDims(m_width, m_height + 2);
789 row_stride2 = m_width;
792 setDims(m_width + 2, m_height);
793 col_stride2 = m_width;
797 ERROR_MESSAGE("neither row-major nor column-major");
812 } else if (pos == 0) {
814 } else if (pos % 2) {
819 for (std::size_t w = 0; w != width; ++w) {
820 PatchControl *p1 = tmp.data() + (w * col_stride);
821 PatchControl *p2 = m_ctrl.data() + (w * col_stride2);
822 for (std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride) {
824 p2 += 2 * row_stride2;
829 p1 = tmp.data() + (w * col_stride + pos * row_stride);
830 p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2);
832 PatchControl *r2a = (p2 + row_stride2);
833 PatchControl *r2b = (p2 - row_stride2);
834 PatchControl *c2a = (p1 - 2 * row_stride);
835 PatchControl *c2b = (p1 - row_stride);
837 // set two new row points
838 *(p2 + 2 * row_stride2) = *p1;
841 for (std::size_t i = 0; i != 3; ++i) {
842 r2a->m_vertex[i] = float_mid(c2b->m_vertex[i], p1->m_vertex[i]);
844 r2b->m_vertex[i] = float_mid(c2a->m_vertex[i], c2b->m_vertex[i]);
846 p2->m_vertex[i] = float_mid(r2a->m_vertex[i], r2b->m_vertex[i]);
848 for (std::size_t i = 0; i != 2; ++i) {
849 r2a->m_texcoord[i] = float_mid(c2b->m_texcoord[i], p1->m_texcoord[i]);
851 r2b->m_texcoord[i] = float_mid(c2a->m_texcoord[i], c2b->m_texcoord[i]);
853 p2->m_texcoord[i] = float_mid(r2a->m_texcoord[i], r2b->m_texcoord[i]);
858 void Patch::RemovePoints(EMatrixMajor mt, bool bFirst)
860 std::size_t width, height, row_stride, col_stride;
865 row_stride = m_width;
870 col_stride = m_width;
876 ERROR_MESSAGE("neither row-major nor column-major");
882 PatchControl *p1 = m_ctrl.data();
883 for (std::size_t w = 0; w != width; ++w, p1 += col_stride) {
885 PatchControl *p2 = p1;
886 for (std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride) {
887 if (0) { //p2->m_selectable.isSelected())
898 PatchControl *p2 = p1;
899 for (std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride) {
900 if (0) { //p2->m_selectable.isSelected())
912 Array<PatchControl> tmp(m_ctrl);
914 std::size_t row_stride2, col_stride2;
917 setDims(m_width, m_height - 2);
919 row_stride2 = m_width;
922 setDims(m_width - 2, m_height);
923 col_stride2 = m_width;
927 ERROR_MESSAGE("neither row-major nor column-major");
941 } else if (pos == 0) {
943 } else if (pos > height - 3) {
945 } else if (pos % 2) {
949 for (std::size_t w = 0; w != width; w++) {
950 PatchControl *p1 = tmp.data() + (w * col_stride);
951 PatchControl *p2 = m_ctrl.data() + (w * col_stride2);
952 for (std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride) {
954 p1 += 2 * row_stride2;
960 p1 = tmp.data() + (w * col_stride + pos * row_stride);
961 p2 = m_ctrl.data() + (w * col_stride2 + pos * row_stride2);
963 for (std::size_t i = 0; i < 3; i++) {
964 (p2 - row_stride2)->m_vertex[i] =
965 ((p1 + 2 * row_stride)->m_vertex[i] + (p1 - 2 * row_stride)->m_vertex[i]) * 0.5f;
967 (p2 - row_stride2)->m_vertex[i] =
968 (p2 - row_stride2)->m_vertex[i] + (2.0f * ((p1)->m_vertex[i] - (p2 - row_stride2)->m_vertex[i]));
970 for (std::size_t i = 0; i < 2; i++) {
971 (p2 - row_stride2)->m_texcoord[i] =
972 ((p1 + 2 * row_stride)->m_texcoord[i] + (p1 - 2 * row_stride)->m_texcoord[i]) * 0.5f;
974 (p2 - row_stride2)->m_texcoord[i] = (p2 - row_stride2)->m_texcoord[i] +
975 (2.0f * ((p1)->m_texcoord[i] - (p2 - row_stride2)->m_texcoord[i]));
980 void Patch::ConstructSeam(EPatchCap eType, Vector3 *p, std::size_t width)
985 m_ctrl[0].m_vertex = p[0];
986 m_ctrl[1].m_vertex = p[1];
987 m_ctrl[2].m_vertex = p[1];
988 m_ctrl[3].m_vertex = p[1];
989 m_ctrl[4].m_vertex = p[1];
990 m_ctrl[5].m_vertex = p[1];
991 m_ctrl[6].m_vertex = p[2];
992 m_ctrl[7].m_vertex = p[1];
993 m_ctrl[8].m_vertex = p[1];
998 Vector3 p3(vector3_added(p[2], vector3_subtracted(p[0], p[1])));
999 m_ctrl[0].m_vertex = p3;
1000 m_ctrl[1].m_vertex = p3;
1001 m_ctrl[2].m_vertex = p[2];
1002 m_ctrl[3].m_vertex = p3;
1003 m_ctrl[4].m_vertex = p3;
1004 m_ctrl[5].m_vertex = p[1];
1005 m_ctrl[6].m_vertex = p3;
1006 m_ctrl[7].m_vertex = p3;
1007 m_ctrl[8].m_vertex = p[0];
1011 Vector3 p5(vector3_mid(p[0], p[4]));
1014 m_ctrl[0].m_vertex = p[0];
1015 m_ctrl[1].m_vertex = p5;
1016 m_ctrl[2].m_vertex = p[4];
1017 m_ctrl[3].m_vertex = p[1];
1018 m_ctrl[4].m_vertex = p[2];
1019 m_ctrl[5].m_vertex = p[3];
1020 m_ctrl[6].m_vertex = p[2];
1021 m_ctrl[7].m_vertex = p[2];
1022 m_ctrl[8].m_vertex = p[2];
1027 m_ctrl[0].m_vertex = p[4];
1028 m_ctrl[1].m_vertex = p[3];
1029 m_ctrl[2].m_vertex = p[2];
1030 m_ctrl[3].m_vertex = p[1];
1031 m_ctrl[4].m_vertex = p[0];
1032 m_ctrl[5].m_vertex = p[3];
1033 m_ctrl[6].m_vertex = p[3];
1034 m_ctrl[7].m_vertex = p[2];
1035 m_ctrl[8].m_vertex = p[1];
1036 m_ctrl[9].m_vertex = p[1];
1037 m_ctrl[10].m_vertex = p[3];
1038 m_ctrl[11].m_vertex = p[3];
1039 m_ctrl[12].m_vertex = p[2];
1040 m_ctrl[13].m_vertex = p[1];
1041 m_ctrl[14].m_vertex = p[1];
1044 case eCapCylinder: {
1045 std::size_t mid = (width - 1) >> 1;
1047 bool degenerate = (mid % 2) != 0;
1049 std::size_t newHeight = mid + (degenerate ? 2 : 1);
1051 setDims(3, newHeight);
1055 for (std::size_t i = width; i != width + 2; ++i) {
1056 p[i] = p[width - 1];
1061 PatchControl *pCtrl = m_ctrl.data();
1062 for (std::size_t i = 0; i != m_height; ++i, pCtrl += m_width) {
1063 pCtrl->m_vertex = p[i];
1067 PatchControl *pCtrl = m_ctrl.data() + 2;
1068 std::size_t h = m_height - 1;
1069 for (std::size_t i = 0; i != m_height; ++i, pCtrl += m_width) {
1070 pCtrl->m_vertex = p[h + (h - i)];
1078 ERROR_MESSAGE("invalid patch-cap type");
1082 controlPointsChanged();
1085 void Patch::ProjectTexture(int nAxis)
1105 ERROR_MESSAGE("invalid axis");
1109 float fWidth = 1 / (m_state->getTexture().width * Texdef_getDefaultTextureScale());
1110 float fHeight = 1 / (m_state->getTexture().height * -Texdef_getDefaultTextureScale());
1112 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
1113 (*i).m_texcoord[0] = (*i).m_vertex[s] * fWidth;
1114 (*i).m_texcoord[1] = (*i).m_vertex[t] * fHeight;
1117 controlPointsChanged();
1120 void Patch::constructPlane(const AABB &aabb, int axis, std::size_t width, std::size_t height)
1122 setDims(width, height);
1142 ERROR_MESSAGE("invalid view-type");
1146 if (m_width < MIN_PATCH_WIDTH || m_width > MAX_PATCH_WIDTH) {
1149 if (m_height < MIN_PATCH_HEIGHT || m_height > MAX_PATCH_HEIGHT) {
1154 vStart[x] = aabb.origin[x] - aabb.extents[x];
1155 vStart[y] = aabb.origin[y] - aabb.extents[y];
1156 vStart[z] = aabb.origin[z];
1158 float xAdj = fabsf((vStart[x] - (aabb.origin[x] + aabb.extents[x])) / (float) (m_width - 1));
1159 float yAdj = fabsf((vStart[y] - (aabb.origin[y] + aabb.extents[y])) / (float) (m_height - 1));
1162 vTmp[z] = vStart[z];
1163 PatchControl *pCtrl = m_ctrl.data();
1165 vTmp[y] = vStart[y];
1166 for (std::size_t h = 0; h < m_height; h++) {
1167 vTmp[x] = vStart[x];
1168 for (std::size_t w = 0; w < m_width; w++, ++pCtrl) {
1169 pCtrl->m_vertex = vTmp;
1178 void Patch::ConstructPrefab(const AABB &aabb, EPatchPrefab eType, int axis, std::size_t width, std::size_t height)
1182 if (eType != ePlane) {
1183 vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
1184 vPos[1] = aabb.origin;
1185 vPos[2] = vector3_added(aabb.origin, aabb.extents);
1188 if (eType == ePlane) {
1189 constructPlane(aabb, axis, width, height);
1190 } else if (eType == eSqCylinder
1191 || eType == eCylinder
1192 || eType == eDenseCylinder
1193 || eType == eVeryDenseCylinder
1195 || eType == eSphere) {
1196 unsigned char *pIndex;
1197 unsigned char pCylIndex[] =
1211 PatchControl *pStart;
1215 pStart = m_ctrl.data();
1217 case eDenseCylinder:
1218 case eVeryDenseCylinder:
1221 pStart = m_ctrl.data() + 1;
1225 pStart = m_ctrl.data() + 1;
1229 pStart = m_ctrl.data() + (9 + 1);
1232 ERROR_MESSAGE("this should be unreachable");
1236 for (std::size_t h = 0; h < 3; h++, pStart += 9) {
1238 PatchControl *pCtrl = pStart;
1239 for (std::size_t w = 0; w < 8; w++, pCtrl++) {
1240 pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
1241 pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
1242 pCtrl->m_vertex[2] = vPos[h][2];
1249 PatchControl *pCtrl = m_ctrl.data();
1250 for (std::size_t h = 0; h < 3; h++, pCtrl += 9) {
1251 pCtrl[8].m_vertex = pCtrl[0].m_vertex;
1255 case eDenseCylinder:
1256 case eVeryDenseCylinder:
1258 PatchControl *pCtrl = m_ctrl.data();
1259 for (std::size_t h = 0; h < 3; h++, pCtrl += 9) {
1260 pCtrl[0].m_vertex = pCtrl[8].m_vertex;
1265 PatchControl *pCtrl = m_ctrl.data();
1266 for (std::size_t h = 0; h < 2; h++, pCtrl += 9) {
1267 pCtrl[0].m_vertex = pCtrl[8].m_vertex;
1271 PatchControl *pCtrl = m_ctrl.data() + 9 * 2;
1272 for (std::size_t w = 0; w < 9; w++, pCtrl++) {
1273 pCtrl->m_vertex[0] = vPos[1][0];
1274 pCtrl->m_vertex[1] = vPos[1][1];
1275 pCtrl->m_vertex[2] = vPos[2][2];
1280 PatchControl *pCtrl = m_ctrl.data() + 9;
1281 for (std::size_t h = 0; h < 3; h++, pCtrl += 9) {
1282 pCtrl[0].m_vertex = pCtrl[8].m_vertex;
1286 PatchControl *pCtrl = m_ctrl.data();
1287 for (std::size_t w = 0; w < 9; w++, pCtrl++) {
1288 pCtrl->m_vertex[0] = vPos[1][0];
1289 pCtrl->m_vertex[1] = vPos[1][1];
1290 pCtrl->m_vertex[2] = vPos[0][2];
1294 PatchControl *pCtrl = m_ctrl.data() + (9 * 4);
1295 for (std::size_t w = 0; w < 9; w++, pCtrl++) {
1296 pCtrl->m_vertex[0] = vPos[1][0];
1297 pCtrl->m_vertex[1] = vPos[1][1];
1298 pCtrl->m_vertex[2] = vPos[2][2];
1303 ERROR_MESSAGE("this should be unreachable");
1306 } else if (eType == eXactCylinder) {
1307 int n = (width - 1) / 2; // n = number of segments
1308 setDims(width, height);
1310 // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
1311 // vPos[1] = aabb.origin;
1312 // vPos[2] = vector3_added(aabb.origin, aabb.extents);
1314 float f = 1 / cos(M_PI / n);
1315 for (std::size_t i = 0; i < width; ++i) {
1316 float angle = (M_PI * i) / n; // 0 to 2pi
1317 float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * cos(angle) * ((i & 1) ? f : 1.0f);
1318 float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle) * ((i & 1) ? f : 1.0f);
1319 for (std::size_t j = 0; j < height; ++j) {
1320 float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float) (height - 1));
1322 v = &m_ctrl.data()[j * width + i];
1328 } else if (eType == eXactCone) {
1329 int n = (width - 1) / 2; // n = number of segments
1330 setDims(width, height);
1332 // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
1333 // vPos[1] = aabb.origin;
1334 // vPos[2] = vector3_added(aabb.origin, aabb.extents);
1336 float f = 1 / cos(M_PI / n);
1337 for (std::size_t i = 0; i < width; ++i) {
1338 float angle = (M_PI * i) / n;
1339 for (std::size_t j = 0; j < height; ++j) {
1340 float x = vPos[1][0] + (1.0f - (j / (float) (height - 1))) * (vPos[2][0] - vPos[1][0]) * cos(angle) *
1341 ((i & 1) ? f : 1.0f);
1342 float y = vPos[1][1] + (1.0f - (j / (float) (height - 1))) * (vPos[2][1] - vPos[1][1]) * sin(angle) *
1343 ((i & 1) ? f : 1.0f);
1344 float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float) (height - 1));
1346 v = &m_ctrl.data()[j * width + i];
1352 } else if (eType == eXactSphere) {
1353 int n = (width - 1) / 2; // n = number of segments (yaw)
1354 int m = (height - 1) / 2; // m = number of segments (pitch)
1355 setDims(width, height);
1357 // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
1358 // vPos[1] = aabb.origin;
1359 // vPos[2] = vector3_added(aabb.origin, aabb.extents);
1361 float f = 1 / cos(M_PI / n);
1362 float g = 1 / cos(M_PI / (2 * m));
1363 for (std::size_t i = 0; i < width; ++i) {
1364 float angle = (M_PI * i) / n;
1365 for (std::size_t j = 0; j < height; ++j) {
1366 float angle2 = (M_PI * j) / (2 * m);
1367 float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * sin(angle2) * ((j & 1) ? g : 1.0f) * cos(angle) *
1368 ((i & 1) ? f : 1.0f);
1369 float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle2) * ((j & 1) ? g : 1.0f) * sin(angle) *
1370 ((i & 1) ? f : 1.0f);
1371 float z = vPos[1][2] + (vPos[2][2] - vPos[1][2]) * -cos(angle2) * ((j & 1) ? g : 1.0f);
1373 v = &m_ctrl.data()[j * width + i];
1379 } else if (eType == eBevel) {
1380 unsigned char *pIndex;
1381 unsigned char pBevIndex[] =
1390 PatchControl *pCtrl = m_ctrl.data();
1391 for (std::size_t h = 0; h < 3; h++) {
1393 for (std::size_t w = 0; w < 3; w++, pIndex += 2, pCtrl++) {
1394 pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
1395 pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
1396 pCtrl->m_vertex[2] = vPos[h][2];
1399 } else if (eType == eEndCap) {
1400 unsigned char *pIndex;
1401 unsigned char pEndIndex[] =
1412 PatchControl *pCtrl = m_ctrl.data();
1413 for (std::size_t h = 0; h < 3; h++) {
1415 for (std::size_t w = 0; w < 5; w++, pIndex += 2, pCtrl++) {
1416 pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
1417 pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
1418 pCtrl->m_vertex[2] = vPos[h][2];
1423 if (eType == eDenseCylinder) {
1424 InsertRemove(true, false, true);
1427 if (eType == eVeryDenseCylinder) {
1428 InsertRemove(true, false, false);
1429 InsertRemove(true, false, true);
1435 void Patch::RenderDebug(RenderStateFlags state) const
1437 for (std::size_t i = 0; i < m_tess.m_numStrips; i++) {
1438 glBegin(GL_QUAD_STRIP);
1439 for (std::size_t j = 0; j < m_tess.m_lenStrips; j++) {
1440 glNormal3fv(normal3f_to_array(
1441 (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->normal));
1442 glTexCoord2fv(texcoord2f_to_array(
1443 (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->texcoord));
1444 glVertex3fv(vertex3f_to_array(
1445 (m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j])->vertex));
1451 void RenderablePatchSolid::RenderNormals() const
1453 const std::size_t width = m_tess.m_numStrips + 1;
1454 const std::size_t height = m_tess.m_lenStrips >> 1;
1456 for (std::size_t i = 0; i < width; i++) {
1457 for (std::size_t j = 0; j < height; j++) {
1461 vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex),
1463 normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->normal), 8)
1466 glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex));
1467 glVertex3fv(&vNormal[0]);
1472 vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex),
1474 normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->tangent), 8)
1477 glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex));
1478 glVertex3fv(&vNormal[0]);
1483 vertex3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->vertex),
1485 normal3f_to_vector3((m_tess.m_vertices.data() + (j * width + i))->bitangent), 8)
1488 glVertex3fv(vertex3f_to_array((m_tess.m_vertices.data() + (j * width + i))->vertex));
1489 glVertex3fv(&vNormal[0]);
1496 const int DEGEN_0a = 0x01;
1497 const int DEGEN_1a = 0x02;
1498 const int DEGEN_2a = 0x04;
1499 const int DEGEN_0b = 0x08;
1500 const int DEGEN_1b = 0x10;
1501 const int DEGEN_2b = 0x20;
1502 const int SPLIT = 0x40;
1503 const int AVERAGE = 0x80;
1506 unsigned int subarray_get_degen(PatchControlIter subarray, std::size_t strideU, std::size_t strideV)
1508 unsigned int nDegen = 0;
1509 const PatchControl *p1;
1510 const PatchControl *p2;
1514 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1519 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1523 p1 = subarray + strideV;
1525 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1530 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1534 p1 = subarray + (strideV << 1);
1536 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1541 if (vector3_equal(p1->m_vertex, p2->m_vertex)) {
1550 deCasteljau3(const Vector3 &P0, const Vector3 &P1, const Vector3 &P2, Vector3 &P01, Vector3 &P12, Vector3 &P012)
1552 P01 = vector3_mid(P0, P1);
1553 P12 = vector3_mid(P1, P2);
1554 P012 = vector3_mid(P01, P12);
1557 inline void BezierInterpolate3(const Vector3 &start, Vector3 &left, Vector3 &mid, Vector3 &right, const Vector3 &end)
1559 left = vector3_mid(start, mid);
1560 right = vector3_mid(mid, end);
1561 mid = vector3_mid(left, right);
1564 inline void BezierInterpolate2(const Vector2 &start, Vector2 &left, Vector2 &mid, Vector2 &right, const Vector2 &end)
1566 left[0] = float_mid(start[0], mid[0]);
1567 left[1] = float_mid(start[1], mid[1]);
1568 right[0] = float_mid(mid[0], end[0]);
1569 right[1] = float_mid(mid[1], end[1]);
1570 mid[0] = float_mid(left[0], right[0]);
1571 mid[1] = float_mid(left[1], right[1]);
1575 inline Vector2 &texcoord_for_index(Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1577 return reinterpret_cast<Vector2 &>( vertices[index].texcoord );
1580 inline Vector3 &vertex_for_index(Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1582 return reinterpret_cast<Vector3 &>( vertices[index].vertex );
1585 inline Vector3 &normal_for_index(Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1587 return reinterpret_cast<Vector3 &>( vertices[index].normal );
1590 inline Vector3 &tangent_for_index(Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1592 return reinterpret_cast<Vector3 &>( vertices[index].tangent );
1595 inline Vector3 &bitangent_for_index(Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1597 return reinterpret_cast<Vector3 &>( vertices[index].bitangent );
1600 inline const Vector2 &texcoord_for_index(const Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1602 return reinterpret_cast<const Vector2 &>( vertices[index].texcoord );
1605 inline const Vector3 &vertex_for_index(const Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1607 return reinterpret_cast<const Vector3 &>( vertices[index].vertex );
1610 inline const Vector3 &normal_for_index(const Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1612 return reinterpret_cast<const Vector3 &>( vertices[index].normal );
1615 inline const Vector3 &tangent_for_index(const Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1617 return reinterpret_cast<const Vector3 &>( vertices[index].tangent );
1620 inline const Vector3 &bitangent_for_index(const Array<ArbitraryMeshVertex> &vertices, std::size_t index)
1622 return reinterpret_cast<const Vector3 &>( vertices[index].bitangent );
1625 #include "math/curve.h"
1627 inline PatchControl QuadraticBezier_evaluate(const PatchControl *firstPoint, double t)
1629 PatchControl result = {Vector3(0, 0, 0), Vector2(0, 0)};
1630 double denominator = 0;
1633 double weight = BernsteinPolynomial<Zero, Two>::apply(t);
1634 vector3_add(result.m_vertex, vector3_scaled(firstPoint[0].m_vertex, weight));
1635 vector2_add(result.m_texcoord, vector2_scaled(firstPoint[0].m_texcoord, weight));
1636 denominator += weight;
1639 double weight = BernsteinPolynomial<One, Two>::apply(t);
1640 vector3_add(result.m_vertex, vector3_scaled(firstPoint[1].m_vertex, weight));
1641 vector2_add(result.m_texcoord, vector2_scaled(firstPoint[1].m_texcoord, weight));
1642 denominator += weight;
1645 double weight = BernsteinPolynomial<Two, Two>::apply(t);
1646 vector3_add(result.m_vertex, vector3_scaled(firstPoint[2].m_vertex, weight));
1647 vector2_add(result.m_texcoord, vector2_scaled(firstPoint[2].m_texcoord, weight));
1648 denominator += weight;
1651 vector3_divide(result.m_vertex, denominator);
1652 vector2_divide(result.m_texcoord, denominator);
1656 inline Vector3 vector3_linear_interpolated(const Vector3 &a, const Vector3 &b, double t)
1658 return vector3_added(vector3_scaled(a, 1.0 - t), vector3_scaled(b, t));
1661 inline Vector2 vector2_linear_interpolated(const Vector2 &a, const Vector2 &b, double t)
1663 return vector2_added(vector2_scaled(a, 1.0 - t), vector2_scaled(b, t));
1666 void normalise_safe(Vector3 &normal)
1668 if (!vector3_equal(normal, g_vector3_identity)) {
1669 vector3_normalise(normal);
1673 inline void QuadraticBezier_evaluate(const PatchControl &a, const PatchControl &b, const PatchControl &c, double t,
1674 PatchControl &point, PatchControl &left, PatchControl &right)
1676 left.m_vertex = vector3_linear_interpolated(a.m_vertex, b.m_vertex, t);
1677 left.m_texcoord = vector2_linear_interpolated(a.m_texcoord, b.m_texcoord, t);
1678 right.m_vertex = vector3_linear_interpolated(b.m_vertex, c.m_vertex, t);
1679 right.m_texcoord = vector2_linear_interpolated(b.m_texcoord, c.m_texcoord, t);
1680 point.m_vertex = vector3_linear_interpolated(left.m_vertex, right.m_vertex, t);
1681 point.m_texcoord = vector2_linear_interpolated(left.m_texcoord, right.m_texcoord, t);
1684 void Patch::TesselateSubMatrixFixed(ArbitraryMeshVertex *vertices, std::size_t strideX, std::size_t strideY,
1685 unsigned int nFlagsX, unsigned int nFlagsY, PatchControl *subMatrix[3][3])
1687 double incrementU = 1.0 / m_subdivisions_x;
1688 double incrementV = 1.0 / m_subdivisions_y;
1689 const std::size_t width = m_subdivisions_x + 1;
1690 const std::size_t height = m_subdivisions_y + 1;
1692 for (std::size_t i = 0; i != width; ++i) {
1693 double tU = (i + 1 == width) ? 1 : i * incrementU;
1694 PatchControl pointX[3];
1695 PatchControl leftX[3];
1696 PatchControl rightX[3];
1697 QuadraticBezier_evaluate(*subMatrix[0][0], *subMatrix[0][1], *subMatrix[0][2], tU, pointX[0], leftX[0],
1699 QuadraticBezier_evaluate(*subMatrix[1][0], *subMatrix[1][1], *subMatrix[1][2], tU, pointX[1], leftX[1],
1701 QuadraticBezier_evaluate(*subMatrix[2][0], *subMatrix[2][1], *subMatrix[2][2], tU, pointX[2], leftX[2],
1704 ArbitraryMeshVertex *p = vertices + i * strideX;
1705 for (std::size_t j = 0; j != height; ++j) {
1706 if ((j == 0 || j + 1 == height) && (i == 0 || i + 1 == width)) {
1708 double tV = (j + 1 == height) ? 1 : j * incrementV;
1710 PatchControl pointY[3];
1711 PatchControl leftY[3];
1712 PatchControl rightY[3];
1713 QuadraticBezier_evaluate(*subMatrix[0][0], *subMatrix[1][0], *subMatrix[2][0], tV, pointY[0], leftY[0],
1715 QuadraticBezier_evaluate(*subMatrix[0][1], *subMatrix[1][1], *subMatrix[2][1], tV, pointY[1], leftY[1],
1717 QuadraticBezier_evaluate(*subMatrix[0][2], *subMatrix[1][2], *subMatrix[2][2], tV, pointY[2], leftY[2],
1723 QuadraticBezier_evaluate(pointX[0], pointX[1], pointX[2], tV, point, left, right);
1726 QuadraticBezier_evaluate(pointY[0], pointY[1], pointY[2], tU, point, up, down);
1728 vertex3f_to_vector3(p->vertex) = point.m_vertex;
1729 texcoord2f_to_vector2(p->texcoord) = point.m_texcoord;
1731 ArbitraryMeshVertex a, b, c;
1733 a.vertex = vertex3f_for_vector3(left.m_vertex);
1734 a.texcoord = texcoord2f_for_vector2(left.m_texcoord);
1735 b.vertex = vertex3f_for_vector3(right.m_vertex);
1736 b.texcoord = texcoord2f_for_vector2(right.m_texcoord);
1739 c.vertex = vertex3f_for_vector3(up.m_vertex);
1740 c.texcoord = texcoord2f_for_vector2(up.m_texcoord);
1742 c.vertex = vertex3f_for_vector3(down.m_vertex);
1743 c.texcoord = texcoord2f_for_vector2(down.m_texcoord);
1746 Vector3 normal = vector3_normalised(
1747 vector3_cross(right.m_vertex - left.m_vertex, up.m_vertex - down.m_vertex));
1749 Vector3 tangent, bitangent;
1750 ArbitraryMeshTriangle_calcTangents(a, b, c, tangent, bitangent);
1751 vector3_normalise(tangent);
1752 vector3_normalise(bitangent);
1754 if (((nFlagsX & AVERAGE) != 0 && i == 0) || ((nFlagsY & AVERAGE) != 0 && j == 0)) {
1755 normal3f_to_vector3(p->normal) = vector3_normalised(
1756 vector3_added(normal3f_to_vector3(p->normal), normal));
1757 normal3f_to_vector3(p->tangent) = vector3_normalised(
1758 vector3_added(normal3f_to_vector3(p->tangent), tangent));
1759 normal3f_to_vector3(p->bitangent) = vector3_normalised(
1760 vector3_added(normal3f_to_vector3(p->bitangent), bitangent));
1762 normal3f_to_vector3(p->normal) = normal;
1763 normal3f_to_vector3(p->tangent) = tangent;
1764 normal3f_to_vector3(p->bitangent) = bitangent;
1773 void Patch::TesselateSubMatrix(const BezierCurveTree *BX, const BezierCurveTree *BY,
1774 std::size_t offStartX, std::size_t offStartY,
1775 std::size_t offEndX, std::size_t offEndY,
1776 std::size_t nFlagsX, std::size_t nFlagsY,
1777 Vector3 &left, Vector3 &mid, Vector3 &right,
1778 Vector2 &texLeft, Vector2 &texMid, Vector2 &texRight,
1781 int newFlagsX, newFlagsY;
1784 Vector3 vertex_0_0, vertex_0_1, vertex_1_0, vertex_1_1, vertex_2_0, vertex_2_1;
1786 Vector2 texcoord_0_0, texcoord_0_1, texcoord_1_0, texcoord_1_1, texcoord_2_0, texcoord_2_1;
1791 BezierInterpolate2(texcoord_for_index(m_tess.m_vertices, offStartX + offStartY),
1793 texcoord_for_index(m_tess.m_vertices, BX->index + offStartY),
1795 texcoord_for_index(m_tess.m_vertices, offEndX + offStartY));
1798 BezierInterpolate2(texcoord_for_index(m_tess.m_vertices, offStartX + offEndY),
1800 texcoord_for_index(m_tess.m_vertices, BX->index + offEndY),
1802 texcoord_for_index(m_tess.m_vertices, offEndX + offEndY));
1806 BezierInterpolate2(texLeft,
1812 if (!BezierCurveTree_isLeaf(BY)) {
1813 texcoord_for_index(m_tess.m_vertices, BX->index + BY->index) = texTmp;
1817 if (!BezierCurveTree_isLeaf(BX->left)) {
1818 texcoord_for_index(m_tess.m_vertices, BX->left->index + offStartY) = texcoord_0_0;
1819 texcoord_for_index(m_tess.m_vertices, BX->left->index + offEndY) = texcoord_2_0;
1821 if (!BezierCurveTree_isLeaf(BY)) {
1822 texcoord_for_index(m_tess.m_vertices, BX->left->index + BY->index) = texcoord_1_0;
1825 if (!BezierCurveTree_isLeaf(BX->right)) {
1826 texcoord_for_index(m_tess.m_vertices, BX->right->index + offStartY) = texcoord_0_1;
1827 texcoord_for_index(m_tess.m_vertices, BX->right->index + offEndY) = texcoord_2_1;
1829 if (!BezierCurveTree_isLeaf(BY)) {
1830 texcoord_for_index(m_tess.m_vertices, BX->right->index + BY->index) = texcoord_1_1;
1837 BezierInterpolate3(vertex_for_index(m_tess.m_vertices, offStartX + offStartY),
1839 vertex_for_index(m_tess.m_vertices, BX->index + offStartY),
1841 vertex_for_index(m_tess.m_vertices, offEndX + offStartY));
1844 BezierInterpolate3(vertex_for_index(m_tess.m_vertices, offStartX + offEndY),
1846 vertex_for_index(m_tess.m_vertices, BX->index + offEndY),
1848 vertex_for_index(m_tess.m_vertices, offEndX + offEndY));
1853 BezierInterpolate3(left,
1859 if (!BezierCurveTree_isLeaf(BY)) {
1860 vertex_for_index(m_tess.m_vertices, BX->index + BY->index) = tmp;
1864 if (!BezierCurveTree_isLeaf(BX->left)) {
1865 vertex_for_index(m_tess.m_vertices, BX->left->index + offStartY) = vertex_0_0;
1866 vertex_for_index(m_tess.m_vertices, BX->left->index + offEndY) = vertex_2_0;
1868 if (!BezierCurveTree_isLeaf(BY)) {
1869 vertex_for_index(m_tess.m_vertices, BX->left->index + BY->index) = vertex_1_0;
1872 if (!BezierCurveTree_isLeaf(BX->right)) {
1873 vertex_for_index(m_tess.m_vertices, BX->right->index + offStartY) = vertex_0_1;
1874 vertex_for_index(m_tess.m_vertices, BX->right->index + offEndY) = vertex_2_1;
1876 if (!BezierCurveTree_isLeaf(BY)) {
1877 vertex_for_index(m_tess.m_vertices, BX->right->index + BY->index) = vertex_1_1;
1883 if (nFlagsX & SPLIT) {
1884 ArbitraryMeshVertex a, b, c;
1887 if (!(nFlagsX & DEGEN_0a) || !(nFlagsX & DEGEN_0b)) {
1888 tangentU = vector3_subtracted(vertex_0_1, vertex_0_0);
1889 a.vertex = vertex3f_for_vector3(vertex_0_0);
1890 a.texcoord = texcoord2f_for_vector2(texcoord_0_0);
1891 c.vertex = vertex3f_for_vector3(vertex_0_1);
1892 c.texcoord = texcoord2f_for_vector2(texcoord_0_1);
1893 } else if (!(nFlagsX & DEGEN_1a) || !(nFlagsX & DEGEN_1b)) {
1894 tangentU = vector3_subtracted(vertex_1_1, vertex_1_0);
1895 a.vertex = vertex3f_for_vector3(vertex_1_0);
1896 a.texcoord = texcoord2f_for_vector2(texcoord_1_0);
1897 c.vertex = vertex3f_for_vector3(vertex_1_1);
1898 c.texcoord = texcoord2f_for_vector2(texcoord_1_1);
1900 tangentU = vector3_subtracted(vertex_2_1, vertex_2_0);
1901 a.vertex = vertex3f_for_vector3(vertex_2_0);
1902 a.texcoord = texcoord2f_for_vector2(texcoord_2_0);
1903 c.vertex = vertex3f_for_vector3(vertex_2_1);
1904 c.texcoord = texcoord2f_for_vector2(texcoord_2_1);
1909 if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_1a) && (nFlagsY & DEGEN_2a)) {
1910 tangentV = vector3_subtracted(vertex_for_index(m_tess.m_vertices, BX->index + offEndY), tmp);
1911 b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offEndY].vertex;
1912 b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offEndY].texcoord;
1914 tangentV = vector3_subtracted(tmp, vertex_for_index(m_tess.m_vertices, BX->index + offStartY));
1915 b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offStartY].vertex;
1916 b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offStartY].texcoord;
1920 Vector3 normal, s, t;
1921 ArbitraryMeshVertex &v = m_tess.m_vertices[offStartY + BX->index];
1922 Vector3 &p = normal3f_to_vector3(v.normal);
1923 Vector3 &ps = normal3f_to_vector3(v.tangent);
1924 Vector3 &pt = normal3f_to_vector3(v.bitangent);
1927 normal = vector3_cross(tangentV, tangentU);
1929 normal = vector3_cross(tangentU, tangentV);
1931 normalise_safe(normal);
1933 ArbitraryMeshTriangle_calcTangents(a, b, c, s, t);
1937 if (nFlagsX & AVERAGE) {
1938 p = vector3_normalised(vector3_added(p, normal));
1939 ps = vector3_normalised(vector3_added(ps, s));
1940 pt = vector3_normalised(vector3_added(pt, t));
1949 ArbitraryMeshVertex a, b, c;
1952 if (!(nFlagsX & DEGEN_2a) || !(nFlagsX & DEGEN_2b)) {
1953 tangentU = vector3_subtracted(vertex_2_1, vertex_2_0);
1954 a.vertex = vertex3f_for_vector3(vertex_2_0);
1955 a.texcoord = texcoord2f_for_vector2(texcoord_2_0);
1956 c.vertex = vertex3f_for_vector3(vertex_2_1);
1957 c.texcoord = texcoord2f_for_vector2(texcoord_2_1);
1958 } else if (!(nFlagsX & DEGEN_1a) || !(nFlagsX & DEGEN_1b)) {
1959 tangentU = vector3_subtracted(vertex_1_1, vertex_1_0);
1960 a.vertex = vertex3f_for_vector3(vertex_1_0);
1961 a.texcoord = texcoord2f_for_vector2(texcoord_1_0);
1962 c.vertex = vertex3f_for_vector3(vertex_1_1);
1963 c.texcoord = texcoord2f_for_vector2(texcoord_1_1);
1965 tangentU = vector3_subtracted(vertex_0_1, vertex_0_0);
1966 a.vertex = vertex3f_for_vector3(vertex_0_0);
1967 a.texcoord = texcoord2f_for_vector2(texcoord_0_0);
1968 c.vertex = vertex3f_for_vector3(vertex_0_1);
1969 c.texcoord = texcoord2f_for_vector2(texcoord_0_1);
1974 if ((nFlagsY & DEGEN_0b) && (nFlagsY & DEGEN_1b) && (nFlagsY & DEGEN_2b)) {
1975 tangentV = vector3_subtracted(tmp, vertex_for_index(m_tess.m_vertices, BX->index + offStartY));
1976 b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offStartY].vertex;
1977 b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offStartY].texcoord;
1979 tangentV = vector3_subtracted(vertex_for_index(m_tess.m_vertices, BX->index + offEndY), tmp);
1980 b.vertex = vertex3f_for_vector3(tmp); //m_tess.m_vertices[BX->index + offEndY].vertex;
1981 b.texcoord = texcoord2f_for_vector2(texTmp); //m_tess.m_vertices[BX->index + offEndY].texcoord;
1984 ArbitraryMeshVertex &v = m_tess.m_vertices[offEndY + BX->index];
1985 Vector3 &p = normal3f_to_vector3(v.normal);
1986 Vector3 &ps = normal3f_to_vector3(v.tangent);
1987 Vector3 &pt = normal3f_to_vector3(v.bitangent);
1990 p = vector3_cross(tangentV, tangentU);
1992 p = vector3_cross(tangentU, tangentV);
1996 ArbitraryMeshTriangle_calcTangents(a, b, c, ps, pt);
2003 newFlagsX = newFlagsY = 0;
2005 if ((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_0b)) {
2006 newFlagsX |= DEGEN_0a;
2007 newFlagsX |= DEGEN_0b;
2009 if ((nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_1b)) {
2010 newFlagsX |= DEGEN_1a;
2011 newFlagsX |= DEGEN_1b;
2013 if ((nFlagsX & DEGEN_2a) && (nFlagsX & DEGEN_2b)) {
2014 newFlagsX |= DEGEN_2a;
2015 newFlagsX |= DEGEN_2b;
2017 if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_1a) && (nFlagsY & DEGEN_2a)) {
2018 newFlagsY |= DEGEN_0a;
2019 newFlagsY |= DEGEN_1a;
2020 newFlagsY |= DEGEN_2a;
2022 if ((nFlagsY & DEGEN_0b) && (nFlagsY & DEGEN_1b) && (nFlagsY & DEGEN_2b)) {
2023 newFlagsY |= DEGEN_0b;
2024 newFlagsY |= DEGEN_1b;
2025 newFlagsY |= DEGEN_2b;
2029 //if((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_2a)) { newFlagsX |= DEGEN_0a; newFlagsX |= DEGEN_1a; newFlagsX |= DEGEN_2a; }
2030 //if((nFlagsX & DEGEN_0b) && (nFlagsX & DEGEN_1b) && (nFlagsX & DEGEN_2b)) { newFlagsX |= DEGEN_0b; newFlagsX |= DEGEN_1b; newFlagsX |= DEGEN_2b; }
2032 newFlagsX |= (nFlagsX & SPLIT);
2033 newFlagsX |= (nFlagsX & AVERAGE);
2035 if (!BezierCurveTree_isLeaf(BY)) {
2037 int nTemp = newFlagsY;
2039 if ((nFlagsY & DEGEN_0a) && (nFlagsY & DEGEN_0b)) {
2040 newFlagsY |= DEGEN_0a;
2041 newFlagsY |= DEGEN_0b;
2043 newFlagsY |= (nFlagsY & SPLIT);
2044 newFlagsY |= (nFlagsY & AVERAGE);
2046 Vector3 &p = vertex_for_index(m_tess.m_vertices, BX->index + BY->index);
2049 Vector2 &p2 = texcoord_for_index(m_tess.m_vertices, BX->index + BY->index);
2052 TesselateSubMatrix(BY, BX->left,
2053 offStartY, offStartX,
2055 newFlagsY, newFlagsX,
2056 vertex_0_0, vertex_1_0, vertex_2_0,
2057 texcoord_0_0, texcoord_1_0, texcoord_2_0,
2065 if ((nFlagsY & DEGEN_2a) && (nFlagsY & DEGEN_2b)) {
2066 newFlagsY |= DEGEN_2a;
2067 newFlagsY |= DEGEN_2b;
2070 TesselateSubMatrix(BY, BX->right,
2071 offStartY, BX->index,
2073 newFlagsY, newFlagsX,
2074 vertex_0_1, vertex_1_1, vertex_2_1,
2075 texcoord_0_1, texcoord_1_1, texcoord_2_1,
2078 if (!BezierCurveTree_isLeaf(BX->left)) {
2079 TesselateSubMatrix(BX->left, BY,
2080 offStartX, offStartY,
2082 newFlagsX, newFlagsY,
2083 left, vertex_1_0, tmp,
2084 texLeft, texcoord_1_0, texTmp,
2088 if (!BezierCurveTree_isLeaf(BX->right)) {
2089 TesselateSubMatrix(BX->right, BY,
2090 BX->index, offStartY,
2092 newFlagsX, newFlagsY,
2093 tmp, vertex_1_1, right,
2094 texTmp, texcoord_1_1, texRight,
2101 void Patch::BuildTesselationCurves(EMatrixMajor major)
2103 std::size_t nArrayStride, length, cross, strideU, strideV;
2107 length = (m_width - 1) >> 1;
2113 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
2118 nArrayStride = m_tess.m_nArrayWidth;
2119 length = (m_height - 1) >> 1;
2125 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
2130 ERROR_MESSAGE("neither row-major nor column-major");
2134 Array<std::size_t> arrayLength(length);
2135 Array<BezierCurveTree *> pCurveTree(length);
2137 std::size_t nArrayLength = 1;
2140 for (Array<std::size_t>::iterator i = arrayLength.begin(); i != arrayLength.end(); ++i) {
2141 *i = Array<std::size_t>::value_type((major == ROW) ? m_subdivisions_x : m_subdivisions_y);
2145 // create a list of the horizontal control curves in each column of sub-patches
2146 // adaptively tesselate each horizontal control curve in the list
2147 // create a binary tree representing the combined tesselation of the list
2148 for (std::size_t i = 0; i != length; ++i) {
2149 PatchControl *p1 = m_ctrlTransformed.data() + (i * 2 * strideU);
2150 GSList *pCurveList = 0;
2151 for (std::size_t j = 0; j < cross; j += 2) {
2152 PatchControl *p2 = p1 + strideV;
2153 PatchControl *p3 = p2 + strideV;
2155 // directly taken from one row of control points
2157 BezierCurve *pCurve = new BezierCurve;
2158 pCurve->crd = (p1 + strideU)->m_vertex;
2159 pCurve->left = p1->m_vertex;
2160 pCurve->right = (p1 + (strideU << 1))->m_vertex;
2161 pCurveList = g_slist_prepend(pCurveList, pCurve);
2164 if (j + 2 >= cross) {
2168 // interpolated from three columns of control points
2170 BezierCurve *pCurve = new BezierCurve;
2171 pCurve->crd = vector3_mid((p1 + strideU)->m_vertex, (p3 + strideU)->m_vertex);
2172 pCurve->left = vector3_mid(p1->m_vertex, p3->m_vertex);
2173 pCurve->right = vector3_mid((p1 + (strideU << 1))->m_vertex, (p3 + (strideU << 1))->m_vertex);
2175 pCurve->crd = vector3_mid(pCurve->crd, (p2 + strideU)->m_vertex);
2176 pCurve->left = vector3_mid(pCurve->left, p2->m_vertex);
2177 pCurve->right = vector3_mid(pCurve->right, (p2 + (strideU << 1))->m_vertex);
2178 pCurveList = g_slist_prepend(pCurveList, pCurve);
2184 pCurveTree[i] = new BezierCurveTree;
2185 BezierCurveTree_FromCurveList(pCurveTree[i], pCurveList);
2186 for (GSList *l = pCurveList; l != 0; l = g_slist_next(l)) {
2187 delete static_cast<BezierCurve *>((*l).data );
2189 g_slist_free(pCurveList);
2191 // set up array indices for binary tree
2192 // accumulate subarray width
2193 arrayLength[i] = Array<std::size_t>::value_type(
2194 BezierCurveTree_Setup(pCurveTree[i], nArrayLength, nArrayStride) - (nArrayLength - 1));
2195 // accumulate total array width
2196 nArrayLength += arrayLength[i];
2202 m_tess.m_nArrayWidth = nArrayLength;
2203 std::swap(m_tess.m_arrayWidth, arrayLength);
2206 std::swap(m_tess.m_curveTreeU, pCurveTree);
2210 m_tess.m_nArrayHeight = nArrayLength;
2211 std::swap(m_tess.m_arrayHeight, arrayLength);
2214 std::swap(m_tess.m_curveTreeV, pCurveTree);
2220 inline void vertex_assign_ctrl(ArbitraryMeshVertex &vertex, const PatchControl &ctrl)
2222 vertex.vertex = vertex3f_for_vector3(ctrl.m_vertex);
2223 vertex.texcoord = texcoord2f_for_vector2(ctrl.m_texcoord);
2226 inline void vertex_clear_normal(ArbitraryMeshVertex &vertex)
2228 vertex.normal = Normal3f(0, 0, 0);
2229 vertex.tangent = Normal3f(0, 0, 0);
2230 vertex.bitangent = Normal3f(0, 0, 0);
2233 inline void tangents_remove_degenerate(Vector3 tangents[6], Vector2 textureTangents[6], unsigned int flags)
2235 if (flags & DEGEN_0a) {
2236 const std::size_t i =
2238 ? (flags & DEGEN_1a)
2239 ? (flags & DEGEN_1b)
2240 ? (flags & DEGEN_2a)
2246 tangents[0] = tangents[i];
2247 textureTangents[0] = textureTangents[i];
2249 if (flags & DEGEN_0b) {
2250 const std::size_t i =
2252 ? (flags & DEGEN_1b)
2253 ? (flags & DEGEN_1a)
2254 ? (flags & DEGEN_2b)
2260 tangents[1] = tangents[i];
2261 textureTangents[1] = textureTangents[i];
2263 if (flags & DEGEN_2a) {
2264 const std::size_t i =
2266 ? (flags & DEGEN_1a)
2267 ? (flags & DEGEN_1b)
2268 ? (flags & DEGEN_0a)
2274 tangents[4] = tangents[i];
2275 textureTangents[4] = textureTangents[i];
2277 if (flags & DEGEN_2b) {
2278 const std::size_t i =
2280 ? (flags & DEGEN_1b)
2281 ? (flags & DEGEN_1a)
2282 ? (flags & DEGEN_0b)
2288 tangents[5] = tangents[i];
2289 textureTangents[5] = textureTangents[i];
2293 void bestTangents00(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1)
2295 if (fabs(dot + length) < 0.001) { // opposing direction = degenerate
2296 if (!(degenerateFlags & DEGEN_1a)) { // if this tangent is degenerate we cannot use it
2299 } else if (!(degenerateFlags & DEGEN_0b)) {
2306 } else if (fabs(dot - length) < 0.001) { // same direction = degenerate
2307 if (degenerateFlags & DEGEN_0b) {
2317 void bestTangents01(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1)
2319 if (fabs(dot - length) < 0.001) { // same direction = degenerate
2320 if (!(degenerateFlags & DEGEN_1a)) { // if this tangent is degenerate we cannot use it
2323 } else if (!(degenerateFlags & DEGEN_2b)) {
2330 } else if (fabs(dot + length) < 0.001) { // opposing direction = degenerate
2331 if (degenerateFlags & DEGEN_2b) {
2341 void bestTangents10(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1)
2343 if (fabs(dot - length) < 0.001) { // same direction = degenerate
2344 if (!(degenerateFlags & DEGEN_1b)) { // if this tangent is degenerate we cannot use it
2347 } else if (!(degenerateFlags & DEGEN_0a)) {
2354 } else if (fabs(dot + length) < 0.001) { // opposing direction = degenerate
2355 if (degenerateFlags & DEGEN_0a) {
2365 void bestTangents11(unsigned int degenerateFlags, double dot, double length, std::size_t &index0, std::size_t &index1)
2367 if (fabs(dot + length) < 0.001) { // opposing direction = degenerate
2368 if (!(degenerateFlags & DEGEN_1b)) { // if this tangent is degenerate we cannot use it
2371 } else if (!(degenerateFlags & DEGEN_2a)) {
2378 } else if (fabs(dot - length) < 0.001) { // same direction = degenerate
2379 if (degenerateFlags & DEGEN_2a) {
2390 Patch::accumulateVertexTangentSpace(std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6],
2391 Vector2 tangentT[6], std::size_t index0, std::size_t index1)
2394 Vector3 normal(vector3_cross(tangentX[index0], tangentY[index1]));
2395 if (!vector3_equal(normal, g_vector3_identity)) {
2396 vector3_add(normal_for_index(m_tess.m_vertices, index), vector3_normalised(normal));
2401 ArbitraryMeshVertex a, b, c;
2402 a.vertex = Vertex3f(0, 0, 0);
2403 a.texcoord = TexCoord2f(0, 0);
2404 b.vertex = vertex3f_for_vector3(tangentX[index0]);
2405 b.texcoord = texcoord2f_for_vector2(tangentS[index0]);
2406 c.vertex = vertex3f_for_vector3(tangentY[index1]);
2407 c.texcoord = texcoord2f_for_vector2(tangentT[index1]);
2410 ArbitraryMeshTriangle_calcTangents(a, b, c, s, t);
2411 if (!vector3_equal(s, g_vector3_identity)) {
2412 vector3_add(tangent_for_index(m_tess.m_vertices, index), vector3_normalised(s));
2414 if (!vector3_equal(t, g_vector3_identity)) {
2415 vector3_add(bitangent_for_index(m_tess.m_vertices, index), vector3_normalised(t));
2420 const std::size_t PATCH_MAX_VERTEX_ARRAY = 1048576;
2422 void Patch::BuildVertexArray()
2424 const std::size_t strideU = 1;
2425 const std::size_t strideV = m_width;
2427 const std::size_t numElems =
2428 m_tess.m_nArrayWidth * m_tess.m_nArrayHeight; // total number of elements in vertex array
2430 const bool bWidthStrips = (m_tess.m_nArrayWidth >=
2431 m_tess.m_nArrayHeight); // decide if horizontal strips are longer than vertical
2434 // allocate vertex, normal, texcoord and primitive-index arrays
2435 m_tess.m_vertices.resize(numElems);
2436 m_tess.m_indices.resize(m_tess.m_nArrayWidth * 2 * (m_tess.m_nArrayHeight - 1));
2438 // set up strip indices
2440 m_tess.m_numStrips = m_tess.m_nArrayHeight - 1;
2441 m_tess.m_lenStrips = m_tess.m_nArrayWidth * 2;
2443 for (std::size_t i = 0; i < m_tess.m_nArrayWidth; i++) {
2444 for (std::size_t j = 0; j < m_tess.m_numStrips; j++) {
2445 m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2] = RenderIndex(j * m_tess.m_nArrayWidth + i);
2446 m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2 + 1] = RenderIndex(
2447 (j + 1) * m_tess.m_nArrayWidth + i);
2448 // reverse because radiant uses CULL_FRONT
2449 //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(j*m_tess.m_nArrayWidth+i);
2450 //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i);
2454 m_tess.m_numStrips = m_tess.m_nArrayWidth - 1;
2455 m_tess.m_lenStrips = m_tess.m_nArrayHeight * 2;
2457 for (std::size_t i = 0; i < m_tess.m_nArrayHeight; i++) {
2458 for (std::size_t j = 0; j < m_tess.m_numStrips; j++) {
2459 m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2] = RenderIndex(
2460 ((m_tess.m_nArrayHeight - 1) - i) * m_tess.m_nArrayWidth + j);
2461 m_tess.m_indices[(j * m_tess.m_lenStrips) + i * 2 + 1] = RenderIndex(
2462 ((m_tess.m_nArrayHeight - 1) - i) * m_tess.m_nArrayWidth + j + 1);
2463 // reverse because radiant uses CULL_FRONT
2464 //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j);
2465 //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1);
2472 PatchControlIter pCtrl = m_ctrlTransformed.data();
2473 for (std::size_t j = 0, offStartY = 0; j + 1 < m_height; j += 2, pCtrl += (strideU + strideV)) {
2474 // set up array offsets for this sub-patch
2475 const bool leafY = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeV[j >> 1]);
2476 const std::size_t offMidY = (m_patchDef3) ? 0 : m_tess.m_curveTreeV[j >> 1]->index;
2477 const std::size_t widthY = m_tess.m_arrayHeight[j >> 1] * m_tess.m_nArrayWidth;
2478 const std::size_t offEndY = offStartY + widthY;
2480 for (std::size_t i = 0, offStartX = 0; i + 1 < m_width; i += 2, pCtrl += (strideU << 1)) {
2481 const bool leafX = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i >> 1]);
2482 const std::size_t offMidX = (m_patchDef3) ? 0 : m_tess.m_curveTreeU[i >> 1]->index;
2483 const std::size_t widthX = m_tess.m_arrayWidth[i >> 1];
2484 const std::size_t offEndX = offStartX + widthX;
2486 PatchControl *subMatrix[3][3];
2487 subMatrix[0][0] = pCtrl;
2488 subMatrix[0][1] = subMatrix[0][0] + strideU;
2489 subMatrix[0][2] = subMatrix[0][1] + strideU;
2490 subMatrix[1][0] = subMatrix[0][0] + strideV;
2491 subMatrix[1][1] = subMatrix[1][0] + strideU;
2492 subMatrix[1][2] = subMatrix[1][1] + strideU;
2493 subMatrix[2][0] = subMatrix[1][0] + strideV;
2494 subMatrix[2][1] = subMatrix[2][0] + strideU;
2495 subMatrix[2][2] = subMatrix[2][1] + strideU;
2497 // assign on-patch control points to vertex array
2498 if (i == 0 && j == 0) {
2499 vertex_clear_normal(m_tess.m_vertices[offStartX + offStartY]);
2501 vertex_assign_ctrl(m_tess.m_vertices[offStartX + offStartY], *subMatrix[0][0]);
2503 vertex_clear_normal(m_tess.m_vertices[offEndX + offStartY]);
2505 vertex_assign_ctrl(m_tess.m_vertices[offEndX + offStartY], *subMatrix[0][2]);
2507 vertex_clear_normal(m_tess.m_vertices[offStartX + offEndY]);
2509 vertex_assign_ctrl(m_tess.m_vertices[offStartX + offEndY], *subMatrix[2][0]);
2511 vertex_clear_normal(m_tess.m_vertices[offEndX + offEndY]);
2512 vertex_assign_ctrl(m_tess.m_vertices[offEndX + offEndY], *subMatrix[2][2]);
2515 // assign remaining control points to vertex array
2517 vertex_assign_ctrl(m_tess.m_vertices[offMidX + offStartY], *subMatrix[0][1]);
2518 vertex_assign_ctrl(m_tess.m_vertices[offMidX + offEndY], *subMatrix[2][1]);
2521 vertex_assign_ctrl(m_tess.m_vertices[offStartX + offMidY], *subMatrix[1][0]);
2522 vertex_assign_ctrl(m_tess.m_vertices[offEndX + offMidY], *subMatrix[1][2]);
2525 vertex_assign_ctrl(m_tess.m_vertices[offMidX + offMidY], *subMatrix[1][1]);
2530 // test all 12 edges for degeneracy
2531 unsigned int nFlagsX = subarray_get_degen(pCtrl, strideU, strideV);
2532 unsigned int nFlagsY = subarray_get_degen(pCtrl, strideV, strideU);
2533 Vector3 tangentX[6], tangentY[6];
2534 Vector2 tangentS[6], tangentT[6];
2536 // set up tangents for each of the 12 edges if they were not degenerate
2537 if (!(nFlagsX & DEGEN_0a)) {
2538 tangentX[0] = vector3_subtracted(subMatrix[0][1]->m_vertex, subMatrix[0][0]->m_vertex);
2539 tangentS[0] = vector2_subtracted(subMatrix[0][1]->m_texcoord, subMatrix[0][0]->m_texcoord);
2541 if (!(nFlagsX & DEGEN_0b)) {
2542 tangentX[1] = vector3_subtracted(subMatrix[0][2]->m_vertex, subMatrix[0][1]->m_vertex);
2543 tangentS[1] = vector2_subtracted(subMatrix[0][2]->m_texcoord, subMatrix[0][1]->m_texcoord);
2545 if (!(nFlagsX & DEGEN_1a)) {
2546 tangentX[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[1][0]->m_vertex);
2547 tangentS[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[1][0]->m_texcoord);
2549 if (!(nFlagsX & DEGEN_1b)) {
2550 tangentX[3] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[1][1]->m_vertex);
2551 tangentS[3] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[1][1]->m_texcoord);
2553 if (!(nFlagsX & DEGEN_2a)) {
2554 tangentX[4] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[2][0]->m_vertex);
2555 tangentS[4] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[2][0]->m_texcoord);
2557 if (!(nFlagsX & DEGEN_2b)) {
2558 tangentX[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[2][1]->m_vertex);
2559 tangentS[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[2][1]->m_texcoord);
2562 if (!(nFlagsY & DEGEN_0a)) {
2563 tangentY[0] = vector3_subtracted(subMatrix[1][0]->m_vertex, subMatrix[0][0]->m_vertex);
2564 tangentT[0] = vector2_subtracted(subMatrix[1][0]->m_texcoord, subMatrix[0][0]->m_texcoord);
2566 if (!(nFlagsY & DEGEN_0b)) {
2567 tangentY[1] = vector3_subtracted(subMatrix[2][0]->m_vertex, subMatrix[1][0]->m_vertex);
2568 tangentT[1] = vector2_subtracted(subMatrix[2][0]->m_texcoord, subMatrix[1][0]->m_texcoord);
2570 if (!(nFlagsY & DEGEN_1a)) {
2571 tangentY[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[0][1]->m_vertex);
2572 tangentT[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[0][1]->m_texcoord);
2574 if (!(nFlagsY & DEGEN_1b)) {
2575 tangentY[3] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[1][1]->m_vertex);
2576 tangentT[3] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[1][1]->m_texcoord);
2578 if (!(nFlagsY & DEGEN_2a)) {
2579 tangentY[4] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[0][2]->m_vertex);
2580 tangentT[4] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[0][2]->m_texcoord);
2582 if (!(nFlagsY & DEGEN_2b)) {
2583 tangentY[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[1][2]->m_vertex);
2584 tangentT[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[1][2]->m_texcoord);
2587 // set up remaining edge tangents by borrowing the tangent from the closest parallel non-degenerate edge
2588 tangents_remove_degenerate(tangentX, tangentS, nFlagsX);
2589 tangents_remove_degenerate(tangentY, tangentT, nFlagsY);
2593 std::size_t index = offStartX + offStartY;
2594 std::size_t index0 = 0;
2595 std::size_t index1 = 0;
2597 double dot = vector3_dot(tangentX[index0], tangentY[index1]);
2598 double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
2600 bestTangents00(nFlagsX, dot, length, index0, index1);
2602 accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
2607 std::size_t index = offEndX + offStartY;
2608 std::size_t index0 = 1;
2609 std::size_t index1 = 4;
2611 double dot = vector3_dot(tangentX[index0], tangentY[index1]);
2612 double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
2614 bestTangents10(nFlagsX, dot, length, index0, index1);
2616 accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
2621 std::size_t index = offStartX + offEndY;
2622 std::size_t index0 = 4;
2623 std::size_t index1 = 1;
2625 double dot = vector3_dot(tangentX[index0], tangentY[index1]);
2626 double length = vector3_length(tangentX[index1]) * vector3_length(tangentY[index1]);
2628 bestTangents01(nFlagsX, dot, length, index0, index1);
2630 accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
2635 std::size_t index = offEndX + offEndY;
2636 std::size_t index0 = 5;
2637 std::size_t index1 = 5;
2639 double dot = vector3_dot(tangentX[index0], tangentY[index1]);
2640 double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
2642 bestTangents11(nFlagsX, dot, length, index0, index1);
2644 accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
2647 //normalise normals that won't be accumulated again
2648 if (i != 0 || j != 0) {
2649 normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offStartY));
2650 normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offStartY));
2651 normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offStartY));
2653 if (i + 3 == m_width) {
2654 normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offStartY));
2655 normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offStartY));
2656 normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offStartY));
2658 if (j + 3 == m_height) {
2659 normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offEndY));
2660 normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offEndY));
2661 normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offEndY));
2663 if (i + 3 == m_width && j + 3 == m_height) {
2664 normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offEndY));
2665 normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offEndY));
2666 normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offEndY));
2669 // set flags to average normals between shared edges
2676 // set flags to save evaluating shared edges twice
2680 // if the patch is curved.. tesselate recursively
2681 // use the relevant control curves for this sub-patch
2683 TesselateSubMatrixFixed(m_tess.m_vertices.data() + offStartX + offStartY, 1, m_tess.m_nArrayWidth,
2684 nFlagsX, nFlagsY, subMatrix);
2687 TesselateSubMatrix(m_tess.m_curveTreeU[i >> 1], m_tess.m_curveTreeV[j >> 1],
2688 offStartX, offStartY, offEndX, offEndY, // array offsets
2690 subMatrix[1][0]->m_vertex, subMatrix[1][1]->m_vertex,
2691 subMatrix[1][2]->m_vertex,
2692 subMatrix[1][0]->m_texcoord, subMatrix[1][1]->m_texcoord,
2693 subMatrix[1][2]->m_texcoord,
2695 } else if (!leafY) {
2696 TesselateSubMatrix(m_tess.m_curveTreeV[j >> 1], m_tess.m_curveTreeU[i >> 1],
2697 offStartY, offStartX, offEndY, offEndX, // array offsets
2699 subMatrix[0][1]->m_vertex, subMatrix[1][1]->m_vertex,
2700 subMatrix[2][1]->m_vertex,
2701 subMatrix[0][1]->m_texcoord, subMatrix[1][1]->m_texcoord,
2702 subMatrix[2][1]->m_texcoord,
2707 offStartX = offEndX;
2709 offStartY = offEndY;
2715 class PatchFilterWrapper : public Filter {
2716 bool m_active = false;
2718 PatchFilter &m_filter;
2720 PatchFilterWrapper(PatchFilter &filter, bool invert) : m_invert(invert), m_filter(filter)
2724 void setActive(bool active)
2734 bool filter(const Patch &patch)
2736 return m_invert ^ m_filter.filter(patch);
2741 typedef std::list<PatchFilterWrapper> PatchFilters;
2742 PatchFilters g_patchFilters;
2744 void add_patch_filter(PatchFilter &filter, int mask, bool invert)
2746 g_patchFilters.push_back(PatchFilterWrapper(filter, invert));
2747 GlobalFilterSystem().addFilter(g_patchFilters.back(), mask);
2750 bool patch_filtered(Patch &patch)
2752 for (PatchFilters::iterator i = g_patchFilters.begin(); i != g_patchFilters.end(); ++i) {
2753 if ((*i).active() && (*i).filter(patch)) {