-inline void vertex_clear_normal(ArbitraryMeshVertex& vertex)
-{
- vertex.normal.x = 0;
- vertex.normal.y = 0;
- vertex.normal.z = 0;
- vertex.tangent.x = 0;
- vertex.tangent.y = 0;
- vertex.tangent.z = 0;
- vertex.bitangent.x = 0;
- vertex.bitangent.y = 0;
- vertex.bitangent.z = 0;
-}
-
-inline void tangents_remove_degenerate(Vector3 tangents[6], Vector2 textureTangents[6], unsigned int flags)
-{
- if(flags & DEGEN_0a)
- {
- const std::size_t i =
- (flags & DEGEN_0b)
- ? (flags & DEGEN_1a)
- ? (flags & DEGEN_1b)
- ? (flags & DEGEN_2a)
- ? 5
- : 4
- : 3
- : 2
- : 1;
- tangents[0] = tangents[i];
- textureTangents[0] = textureTangents[i];
- }
- if(flags & DEGEN_0b)
- {
- const std::size_t i =
- (flags & DEGEN_0a)
- ? (flags & DEGEN_1b)
- ? (flags & DEGEN_1a)
- ? (flags & DEGEN_2b)
- ? 4
- : 5
- : 2
- : 3
- : 0;
- tangents[1] = tangents[i];
- textureTangents[1] = textureTangents[i];
- }
- if(flags & DEGEN_2a)
- {
- const std::size_t i =
- (flags & DEGEN_2b)
- ? (flags & DEGEN_1a)
- ? (flags & DEGEN_1b)
- ? (flags & DEGEN_0a)
- ? 1
- : 0
- : 3
- : 2
- : 5;
- tangents[4] = tangents[i];
- textureTangents[4] = textureTangents[i];
- }
- if(flags & DEGEN_2b)
- {
- const std::size_t i =
- (flags & DEGEN_2a)
- ? (flags & DEGEN_1b)
- ? (flags & DEGEN_1a)
- ? (flags & DEGEN_0b)
- ? 0
- : 1
- : 2
- : 3
- : 4;
- tangents[5] = tangents[i];
- textureTangents[5] = textureTangents[i];
- }
-}
-
-void bestTangents00(unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1)
-{
- if(fabs(dot + length) < 0.001) // opposing direction = degenerate
- {
- if(!(degenerateFlags & DEGEN_1a)) // if this tangent is degenerate we cannot use it
- {
- index0 = 2;
- index1 = 0;
- }
- else if(!(degenerateFlags & DEGEN_0b))
- {
- index0 = 0;
- index1 = 1;
- }
- else
- {
- index0 = 1;
- index1 = 0;
- }
- }
- else if(fabs(dot - length) < 0.001) // same direction = degenerate
- {
- if(degenerateFlags & DEGEN_0b)
- {
- index0 = 0;
- index1 = 1;
- }
- else
- {
- index0 = 1;
- index1 = 0;
- }
- }
-}
-
-void bestTangents01(unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1)
-{
- if(fabs(dot - length) < 0.001) // same direction = degenerate
- {
- if(!(degenerateFlags & DEGEN_1a)) // if this tangent is degenerate we cannot use it
- {
- index0 = 2;
- index1 = 1;
- }
- else if(!(degenerateFlags & DEGEN_2b))
- {
- index0 = 4;
- index1 = 0;
- }
- else
- {
- index0 = 5;
- index1 = 1;
- }
- }
- else if(fabs(dot + length) < 0.001) // opposing direction = degenerate
- {
- if(degenerateFlags & DEGEN_2b)
- {
- index0 = 4;
- index1 = 0;
- }
- else
- {
- index0 = 5;
- index1 = 1;
- }
- }
-}
-
-void bestTangents10(unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1)
-{
- if(fabs(dot - length) < 0.001) // same direction = degenerate
- {
- if(!(degenerateFlags & DEGEN_1b)) // if this tangent is degenerate we cannot use it
- {
- index0 = 3;
- index1 = 4;
- }
- else if(!(degenerateFlags & DEGEN_0a))
- {
- index0 = 1;
- index1 = 5;
- }
- else
- {
- index0 = 0;
- index1 = 4;
- }
- }
- else if(fabs(dot + length) < 0.001) // opposing direction = degenerate
- {
- if(degenerateFlags & DEGEN_0a)
- {
- index0 = 1;
- index1 = 5;
- }
- else
- {
- index0 = 0;
- index1 = 4;
- }
- }
-}
-
-void bestTangents11(unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1)
-{
- if(fabs(dot + length) < 0.001) // opposing direction = degenerate
- {
- if(!(degenerateFlags & DEGEN_1b)) // if this tangent is degenerate we cannot use it
- {
- index0 = 3;
- index1 = 5;
- }
- else if(!(degenerateFlags & DEGEN_2a))
- {
- index0 = 5;
- index1 = 4;
- }
- else
- {
- index0 = 4;
- index1 = 5;
- }
- }
- else if(fabs(dot - length) < 0.001) // same direction = degenerate
- {
- if(degenerateFlags & DEGEN_2a)
- {
- index0 = 5;
- index1 = 4;
- }
- else
- {
- index0 = 4;
- index1 = 5;
- }
- }
-}
-
-void Patch::accumulateVertexTangentSpace(std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6], Vector2 tangentT[6], std::size_t index0, std::size_t index1)
-{
- {
- Vector3 normal(vector3_cross(tangentX[index0], tangentY[index1]));
- if(!vector3_equal(normal, g_vector3_identity))
- {
- vector3_add(normal_for_index(m_tess.m_vertices, index), vector3_normalised(normal));
- }
- }
-
- {
- ArbitraryMeshVertex a, b, c;
- a.vertex = Vertex3f(0, 0, 0);
- a.texcoord = TexCoord2f(0, 0);
- b.vertex = vertex3f_for_vector3(tangentX[index0]);
- b.texcoord = texcoord2f_for_vector2(tangentS[index0]);
- c.vertex = vertex3f_for_vector3(tangentY[index1]);
- c.texcoord = texcoord2f_for_vector2(tangentT[index1]);
-
- Vector3 s, t;
- ArbitraryMeshTriangle_calcTangents(a, b, c, s, t);
- if(!vector3_equal(s, g_vector3_identity))
- {
- vector3_add(tangent_for_index(m_tess.m_vertices, index), vector3_normalised(s));
- }
- if(!vector3_equal(t, g_vector3_identity))
- {
- vector3_add(bitangent_for_index(m_tess.m_vertices, index), vector3_normalised(t));
- }
- }
-}
-
-void Patch::BuildVertexArray()
-{
- const std::size_t strideU = 1;
- const std::size_t strideV = m_width;
-
- const std::size_t numElems = m_tess.m_nArrayWidth*m_tess.m_nArrayHeight; // total number of elements in vertex array
-
- const bool bWidthStrips = (m_tess.m_nArrayWidth >= m_tess.m_nArrayHeight); // decide if horizontal strips are longer than vertical
-
-
- // allocate vertex, normal, texcoord and primitive-index arrays
- m_tess.m_vertices.resize(numElems);
- m_tess.m_indices.resize(m_tess.m_nArrayWidth *2 * (m_tess.m_nArrayHeight - 1));
-
- // set up strip indices
- if(bWidthStrips)
- {
- m_tess.m_numStrips = m_tess.m_nArrayHeight-1;
- m_tess.m_lenStrips = m_tess.m_nArrayWidth*2;
-
- for(std::size_t i=0; i<m_tess.m_nArrayWidth; i++)
- {
- for(std::size_t j=0; j<m_tess.m_numStrips; j++)
- {
- m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(j*m_tess.m_nArrayWidth+i);
- m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i);
- // reverse because radiant uses CULL_FRONT
- //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(j*m_tess.m_nArrayWidth+i);
- //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i);
- }
- }
- }
- else
- {
- m_tess.m_numStrips = m_tess.m_nArrayWidth-1;
- m_tess.m_lenStrips = m_tess.m_nArrayHeight*2;
-
- for(std::size_t i=0; i<m_tess.m_nArrayHeight; i++)
- {
- for(std::size_t j=0; j<m_tess.m_numStrips; j++)
- {
- m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j);
- m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1);
- // reverse because radiant uses CULL_FRONT
- //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j);
- //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1);
-
- }
- }
- }
-
- {
- PatchControlIter pCtrl = m_ctrlTransformed.data();
- for(std::size_t j = 0, offStartY = 0; j+1 < m_height; j += 2, pCtrl += (strideU + strideV))
- {
- // set up array offsets for this sub-patch
- const bool leafY = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeV[j>>1]);
- const std::size_t offMidY = (m_patchDef3) ? 0 : m_tess.m_curveTreeV[j>>1]->index;
- const std::size_t widthY = m_tess.m_arrayHeight[j>>1] * m_tess.m_nArrayWidth;
- const std::size_t offEndY = offStartY + widthY;
-
- for(std::size_t i = 0, offStartX = 0; i+1 < m_width; i += 2, pCtrl += (strideU << 1))
- {
- const bool leafX = (m_patchDef3) ? false : BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i>>1]);
- const std::size_t offMidX = (m_patchDef3) ? 0 : m_tess.m_curveTreeU[i>>1]->index;
- const std::size_t widthX = m_tess.m_arrayWidth[i>>1];
- const std::size_t offEndX = offStartX + widthX;
-
- PatchControl *subMatrix[3][3];
- subMatrix[0][0] = pCtrl;
- subMatrix[0][1] = subMatrix[0][0]+strideU;
- subMatrix[0][2] = subMatrix[0][1]+strideU;
- subMatrix[1][0] = subMatrix[0][0]+strideV;
- subMatrix[1][1] = subMatrix[1][0]+strideU;
- subMatrix[1][2] = subMatrix[1][1]+strideU;
- subMatrix[2][0] = subMatrix[1][0]+strideV;
- subMatrix[2][1] = subMatrix[2][0]+strideU;
- subMatrix[2][2] = subMatrix[2][1]+strideU;
-
- // assign on-patch control points to vertex array
- if(i == 0 && j == 0)
- {
- vertex_clear_normal(m_tess.m_vertices[offStartX + offStartY]);
- }
- vertex_assign_ctrl(m_tess.m_vertices[offStartX + offStartY], *subMatrix[0][0]);
- if(j == 0)
- {
- vertex_clear_normal(m_tess.m_vertices[offEndX + offStartY]);
- }
- vertex_assign_ctrl(m_tess.m_vertices[offEndX + offStartY], *subMatrix[0][2]);
- if(i == 0)
- {
- vertex_clear_normal(m_tess.m_vertices[offStartX + offEndY]);
- }
- vertex_assign_ctrl(m_tess.m_vertices[offStartX + offEndY], *subMatrix[2][0]);
-
- vertex_clear_normal(m_tess.m_vertices[offEndX + offEndY]);
- vertex_assign_ctrl(m_tess.m_vertices[offEndX + offEndY], *subMatrix[2][2]);
-
- if(!m_patchDef3)
- {
- // assign remaining control points to vertex array
- if(!leafX)
- {
- vertex_assign_ctrl(m_tess.m_vertices[offMidX + offStartY], *subMatrix[0][1]);
- vertex_assign_ctrl(m_tess.m_vertices[offMidX + offEndY], *subMatrix[2][1]);
- }
- if(!leafY)
- {
- vertex_assign_ctrl(m_tess.m_vertices[offStartX + offMidY], *subMatrix[1][0]);
- vertex_assign_ctrl(m_tess.m_vertices[offEndX + offMidY], *subMatrix[1][2]);
-
- if(!leafX)
- {
- vertex_assign_ctrl(m_tess.m_vertices[offMidX + offMidY], *subMatrix[1][1]);
- }
- }
- }
-
- // test all 12 edges for degeneracy
- unsigned int nFlagsX = subarray_get_degen(pCtrl, strideU, strideV);
- unsigned int nFlagsY = subarray_get_degen(pCtrl, strideV, strideU);
- Vector3 tangentX[6], tangentY[6];
- Vector2 tangentS[6], tangentT[6];
-
- // set up tangents for each of the 12 edges if they were not degenerate
- if(!(nFlagsX & DEGEN_0a))
- {
- tangentX[0] = vector3_subtracted(subMatrix[0][1]->m_vertex, subMatrix[0][0]->m_vertex);
- tangentS[0] = vector2_subtracted(subMatrix[0][1]->m_texcoord, subMatrix[0][0]->m_texcoord);
- }
- if(!(nFlagsX & DEGEN_0b))
- {
- tangentX[1] = vector3_subtracted(subMatrix[0][2]->m_vertex, subMatrix[0][1]->m_vertex);
- tangentS[1] = vector2_subtracted(subMatrix[0][2]->m_texcoord, subMatrix[0][1]->m_texcoord);
- }
- if(!(nFlagsX & DEGEN_1a))
- {
- tangentX[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[1][0]->m_vertex);
- tangentS[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[1][0]->m_texcoord);
- }
- if(!(nFlagsX & DEGEN_1b))
- {
- tangentX[3] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[1][1]->m_vertex);
- tangentS[3] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[1][1]->m_texcoord);
- }
- if(!(nFlagsX & DEGEN_2a))
- {
- tangentX[4] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[2][0]->m_vertex);
- tangentS[4] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[2][0]->m_texcoord);
- }
- if(!(nFlagsX & DEGEN_2b))
- {
- tangentX[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[2][1]->m_vertex);
- tangentS[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[2][1]->m_texcoord);
- }
-
- if(!(nFlagsY & DEGEN_0a))
- {
- tangentY[0] = vector3_subtracted(subMatrix[1][0]->m_vertex, subMatrix[0][0]->m_vertex);
- tangentT[0] = vector2_subtracted(subMatrix[1][0]->m_texcoord, subMatrix[0][0]->m_texcoord);
- }
- if(!(nFlagsY & DEGEN_0b))
- {
- tangentY[1] = vector3_subtracted(subMatrix[2][0]->m_vertex, subMatrix[1][0]->m_vertex);
- tangentT[1] = vector2_subtracted(subMatrix[2][0]->m_texcoord, subMatrix[1][0]->m_texcoord);
- }
- if(!(nFlagsY & DEGEN_1a))
- {
- tangentY[2] = vector3_subtracted(subMatrix[1][1]->m_vertex, subMatrix[0][1]->m_vertex);
- tangentT[2] = vector2_subtracted(subMatrix[1][1]->m_texcoord, subMatrix[0][1]->m_texcoord);
- }
- if(!(nFlagsY & DEGEN_1b))
- {
- tangentY[3] = vector3_subtracted(subMatrix[2][1]->m_vertex, subMatrix[1][1]->m_vertex);
- tangentT[3] = vector2_subtracted(subMatrix[2][1]->m_texcoord, subMatrix[1][1]->m_texcoord);
- }
- if(!(nFlagsY & DEGEN_2a))
- {
- tangentY[4] = vector3_subtracted(subMatrix[1][2]->m_vertex, subMatrix[0][2]->m_vertex);
- tangentT[4] = vector2_subtracted(subMatrix[1][2]->m_texcoord, subMatrix[0][2]->m_texcoord);
- }
- if(!(nFlagsY & DEGEN_2b))
- {
- tangentY[5] = vector3_subtracted(subMatrix[2][2]->m_vertex, subMatrix[1][2]->m_vertex);
- tangentT[5] = vector2_subtracted(subMatrix[2][2]->m_texcoord, subMatrix[1][2]->m_texcoord);
- }
-
- // set up remaining edge tangents by borrowing the tangent from the closest parallel non-degenerate edge
- tangents_remove_degenerate(tangentX, tangentS, nFlagsX);
- tangents_remove_degenerate(tangentY, tangentT, nFlagsY);
-
- {
- // x=0, y=0
- std::size_t index = offStartX + offStartY;
- std::size_t index0 = 0;
- std::size_t index1 = 0;
-
- double dot = vector3_dot(tangentX[index0], tangentY[index1]);
- double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
-
- bestTangents00(nFlagsX, dot, length, index0, index1);
-
- accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
- }
-
- {
- // x=1, y=0
- std::size_t index = offEndX + offStartY;
- std::size_t index0 = 1;
- std::size_t index1 = 4;
-
- double dot = vector3_dot(tangentX[index0],tangentY[index1]);
- double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
-
- bestTangents10(nFlagsX, dot, length, index0, index1);
-
- accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
- }
-
- {
- // x=0, y=1
- std::size_t index = offStartX + offEndY;
- std::size_t index0 = 4;
- std::size_t index1 = 1;
-
- double dot = vector3_dot(tangentX[index0], tangentY[index1]);
- double length = vector3_length(tangentX[index1]) * vector3_length(tangentY[index1]);
-
- bestTangents01(nFlagsX, dot, length, index0, index1);
-
- accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
- }
-
- {
- // x=1, y=1
- std::size_t index = offEndX + offEndY;
- std::size_t index0 = 5;
- std::size_t index1 = 5;
-
- double dot = vector3_dot(tangentX[index0],tangentY[index1]);
- double length = vector3_length(tangentX[index0]) * vector3_length(tangentY[index1]);
-
- bestTangents11(nFlagsX, dot, length, index0, index1);
-
- accumulateVertexTangentSpace(index, tangentX, tangentY, tangentS, tangentT, index0, index1);
- }
-
- //normalise normals that won't be accumulated again
- if(i!=0 || j!=0)
- {
- normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offStartY));
- normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offStartY));
- normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offStartY));
- }
- if(i+3 == m_width)
- {
- normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offStartY));
- normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offStartY));
- normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offStartY));
- }
- if(j+3 == m_height)
- {
- normalise_safe(normal_for_index(m_tess.m_vertices, offStartX + offEndY));
- normalise_safe(tangent_for_index(m_tess.m_vertices, offStartX + offEndY));
- normalise_safe(bitangent_for_index(m_tess.m_vertices, offStartX + offEndY));
- }
- if(i+3 == m_width && j+3 == m_height)
- {
- normalise_safe(normal_for_index(m_tess.m_vertices, offEndX + offEndY));
- normalise_safe(tangent_for_index(m_tess.m_vertices, offEndX + offEndY));
- normalise_safe(bitangent_for_index(m_tess.m_vertices, offEndX + offEndY));
- }
-
- // set flags to average normals between shared edges
- if(j != 0)
- {
- nFlagsX |= AVERAGE;
- }
- if(i != 0)
- {
- nFlagsY |= AVERAGE;
- }
- // set flags to save evaluating shared edges twice
- nFlagsX |= SPLIT;
- nFlagsY |= SPLIT;
-
- // if the patch is curved.. tesselate recursively
- // use the relevant control curves for this sub-patch
- if(m_patchDef3)
- {
- TesselateSubMatrixFixed(m_tess.m_vertices.data() + offStartX + offStartY, 1, m_tess.m_nArrayWidth, nFlagsX, nFlagsY, subMatrix);
- }
- else
- {
- if(!leafX)
- {
- TesselateSubMatrix( m_tess.m_curveTreeU[i>>1], m_tess.m_curveTreeV[j>>1],
- offStartX, offStartY, offEndX, offEndY, // array offsets
- nFlagsX, nFlagsY,
- subMatrix[1][0]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[1][2]->m_vertex,
- subMatrix[1][0]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[1][2]->m_texcoord,
- false );
- }
- else if(!leafY)
- {
- TesselateSubMatrix( m_tess.m_curveTreeV[j>>1], m_tess.m_curveTreeU[i>>1],
- offStartY, offStartX, offEndY, offEndX, // array offsets
- nFlagsY, nFlagsX,
- subMatrix[0][1]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[2][1]->m_vertex,
- subMatrix[0][1]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[2][1]->m_texcoord,
- true );
- }
- }
-
- offStartX = offEndX;
- }
- offStartY = offEndY;
- }
- }
+ Vector3 tmp;
+ Vector3 vertex_0_0, vertex_0_1, vertex_1_0, vertex_1_1, vertex_2_0, vertex_2_1;
+ Vector2 texTmp;
+ Vector2 texcoord_0_0, texcoord_0_1, texcoord_1_0, texcoord_1_1, texcoord_2_0, texcoord_2_1;
+
+ {
+ // texcoords
+
+ BezierInterpolate2( texcoord_for_index( m_tess.m_vertices, offStartX + offStartY ),
+ texcoord_0_0,
+ texcoord_for_index( m_tess.m_vertices, BX->index + offStartY ),
+ texcoord_0_1,
+ texcoord_for_index( m_tess.m_vertices, offEndX + offStartY ) );
+
+
+ BezierInterpolate2( texcoord_for_index( m_tess.m_vertices, offStartX + offEndY ),
+ texcoord_2_0,
+ texcoord_for_index( m_tess.m_vertices, BX->index + offEndY ),
+ texcoord_2_1,
+ texcoord_for_index( m_tess.m_vertices, offEndX + offEndY ) );
+
+ texTmp = texMid;
+
+ BezierInterpolate2( texLeft,
+ texcoord_1_0,
+ texTmp,
+ texcoord_1_1,
+ texRight );
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ texcoord_for_index( m_tess.m_vertices, BX->index + BY->index ) = texTmp;
+ }
+
+
+ if ( !BezierCurveTree_isLeaf( BX->left ) ) {
+ texcoord_for_index( m_tess.m_vertices, BX->left->index + offStartY ) = texcoord_0_0;
+ texcoord_for_index( m_tess.m_vertices, BX->left->index + offEndY ) = texcoord_2_0;
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ texcoord_for_index( m_tess.m_vertices, BX->left->index + BY->index ) = texcoord_1_0;
+ }
+ }
+ if ( !BezierCurveTree_isLeaf( BX->right ) ) {
+ texcoord_for_index( m_tess.m_vertices, BX->right->index + offStartY ) = texcoord_0_1;
+ texcoord_for_index( m_tess.m_vertices, BX->right->index + offEndY ) = texcoord_2_1;
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ texcoord_for_index( m_tess.m_vertices, BX->right->index + BY->index ) = texcoord_1_1;
+ }
+ }
+
+
+ // verts
+
+ BezierInterpolate3( vertex_for_index( m_tess.m_vertices, offStartX + offStartY ),
+ vertex_0_0,
+ vertex_for_index( m_tess.m_vertices, BX->index + offStartY ),
+ vertex_0_1,
+ vertex_for_index( m_tess.m_vertices, offEndX + offStartY ) );
+
+
+ BezierInterpolate3( vertex_for_index( m_tess.m_vertices, offStartX + offEndY ),
+ vertex_2_0,
+ vertex_for_index( m_tess.m_vertices, BX->index + offEndY ),
+ vertex_2_1,
+ vertex_for_index( m_tess.m_vertices, offEndX + offEndY ) );
+
+
+ tmp = mid;
+
+ BezierInterpolate3( left,
+ vertex_1_0,
+ tmp,
+ vertex_1_1,
+ right );
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ vertex_for_index( m_tess.m_vertices, BX->index + BY->index ) = tmp;
+ }
+
+
+ if ( !BezierCurveTree_isLeaf( BX->left ) ) {
+ vertex_for_index( m_tess.m_vertices, BX->left->index + offStartY ) = vertex_0_0;
+ vertex_for_index( m_tess.m_vertices, BX->left->index + offEndY ) = vertex_2_0;
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ vertex_for_index( m_tess.m_vertices, BX->left->index + BY->index ) = vertex_1_0;
+ }
+ }
+ if ( !BezierCurveTree_isLeaf( BX->right ) ) {
+ vertex_for_index( m_tess.m_vertices, BX->right->index + offStartY ) = vertex_0_1;
+ vertex_for_index( m_tess.m_vertices, BX->right->index + offEndY ) = vertex_2_1;
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ vertex_for_index( m_tess.m_vertices, BX->right->index + BY->index ) = vertex_1_1;
+ }
+ }
+
+ // normals
+
+ if ( nFlagsX & SPLIT ) {
+ ArbitraryMeshVertex a, b, c;
+ Vector3 tangentU;
+
+ if ( !( nFlagsX & DEGEN_0a ) || !( nFlagsX & DEGEN_0b ) ) {
+ tangentU = vector3_subtracted( vertex_0_1, vertex_0_0 );
+ a.vertex = vertex3f_for_vector3( vertex_0_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_0_0 );
+ c.vertex = vertex3f_for_vector3( vertex_0_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_0_1 );
+ }
+ else if ( !( nFlagsX & DEGEN_1a ) || !( nFlagsX & DEGEN_1b ) ) {
+ tangentU = vector3_subtracted( vertex_1_1, vertex_1_0 );
+ a.vertex = vertex3f_for_vector3( vertex_1_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_1_0 );
+ c.vertex = vertex3f_for_vector3( vertex_1_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_1_1 );
+ }
+ else
+ {
+ tangentU = vector3_subtracted( vertex_2_1, vertex_2_0 );
+ a.vertex = vertex3f_for_vector3( vertex_2_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_2_0 );
+ c.vertex = vertex3f_for_vector3( vertex_2_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_2_1 );
+ }
+
+ Vector3 tangentV;
+
+ if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_1a ) && ( nFlagsY & DEGEN_2a ) ) {
+ tangentV = vector3_subtracted( vertex_for_index( m_tess.m_vertices, BX->index + offEndY ), tmp );
+ b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offEndY].vertex;
+ b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offEndY].texcoord;
+ }
+ else
+ {
+ tangentV = vector3_subtracted( tmp, vertex_for_index( m_tess.m_vertices, BX->index + offStartY ) );
+ b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offStartY].vertex;
+ b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offStartY].texcoord;
+ }
+
+
+ Vector3 normal, s, t;
+ ArbitraryMeshVertex& v = m_tess.m_vertices[offStartY + BX->index];
+ Vector3& p = normal3f_to_vector3( v.normal );
+ Vector3& ps = normal3f_to_vector3( v.tangent );
+ Vector3& pt = normal3f_to_vector3( v.bitangent );
+
+ if ( bTranspose ) {
+ normal = vector3_cross( tangentV, tangentU );
+ }
+ else
+ {
+ normal = vector3_cross( tangentU, tangentV );
+ }
+ normalise_safe( normal );
+
+ ArbitraryMeshTriangle_calcTangents( a, b, c, s, t );
+ normalise_safe( s );
+ normalise_safe( t );
+
+ if ( nFlagsX & AVERAGE ) {
+ p = vector3_normalised( vector3_added( p, normal ) );
+ ps = vector3_normalised( vector3_added( ps, s ) );
+ pt = vector3_normalised( vector3_added( pt, t ) );
+ }
+ else
+ {
+ p = normal;
+ ps = s;
+ pt = t;
+ }
+ }
+
+ {
+ ArbitraryMeshVertex a, b, c;
+ Vector3 tangentU;
+
+ if ( !( nFlagsX & DEGEN_2a ) || !( nFlagsX & DEGEN_2b ) ) {
+ tangentU = vector3_subtracted( vertex_2_1, vertex_2_0 );
+ a.vertex = vertex3f_for_vector3( vertex_2_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_2_0 );
+ c.vertex = vertex3f_for_vector3( vertex_2_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_2_1 );
+ }
+ else if ( !( nFlagsX & DEGEN_1a ) || !( nFlagsX & DEGEN_1b ) ) {
+ tangentU = vector3_subtracted( vertex_1_1, vertex_1_0 );
+ a.vertex = vertex3f_for_vector3( vertex_1_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_1_0 );
+ c.vertex = vertex3f_for_vector3( vertex_1_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_1_1 );
+ }
+ else
+ {
+ tangentU = vector3_subtracted( vertex_0_1, vertex_0_0 );
+ a.vertex = vertex3f_for_vector3( vertex_0_0 );
+ a.texcoord = texcoord2f_for_vector2( texcoord_0_0 );
+ c.vertex = vertex3f_for_vector3( vertex_0_1 );
+ c.texcoord = texcoord2f_for_vector2( texcoord_0_1 );
+ }
+
+ Vector3 tangentV;
+
+ if ( ( nFlagsY & DEGEN_0b ) && ( nFlagsY & DEGEN_1b ) && ( nFlagsY & DEGEN_2b ) ) {
+ tangentV = vector3_subtracted( tmp, vertex_for_index( m_tess.m_vertices, BX->index + offStartY ) );
+ b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offStartY].vertex;
+ b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offStartY].texcoord;
+ }
+ else
+ {
+ tangentV = vector3_subtracted( vertex_for_index( m_tess.m_vertices, BX->index + offEndY ), tmp );
+ b.vertex = vertex3f_for_vector3( tmp ); //m_tess.m_vertices[BX->index + offEndY].vertex;
+ b.texcoord = texcoord2f_for_vector2( texTmp ); //m_tess.m_vertices[BX->index + offEndY].texcoord;
+ }
+
+ ArbitraryMeshVertex& v = m_tess.m_vertices[offEndY + BX->index];
+ Vector3& p = normal3f_to_vector3( v.normal );
+ Vector3& ps = normal3f_to_vector3( v.tangent );
+ Vector3& pt = normal3f_to_vector3( v.bitangent );
+
+ if ( bTranspose ) {
+ p = vector3_cross( tangentV, tangentU );
+ }
+ else
+ {
+ p = vector3_cross( tangentU, tangentV );
+ }
+ normalise_safe( p );
+
+ ArbitraryMeshTriangle_calcTangents( a, b, c, ps, pt );
+ normalise_safe( ps );
+ normalise_safe( pt );
+ }
+ }
+
+
+ newFlagsX = newFlagsY = 0;
+
+ if ( ( nFlagsX & DEGEN_0a ) && ( nFlagsX & DEGEN_0b ) ) {
+ newFlagsX |= DEGEN_0a;
+ newFlagsX |= DEGEN_0b;
+ }
+ if ( ( nFlagsX & DEGEN_1a ) && ( nFlagsX & DEGEN_1b ) ) {
+ newFlagsX |= DEGEN_1a;
+ newFlagsX |= DEGEN_1b;
+ }
+ if ( ( nFlagsX & DEGEN_2a ) && ( nFlagsX & DEGEN_2b ) ) {
+ newFlagsX |= DEGEN_2a;
+ newFlagsX |= DEGEN_2b;
+ }
+ if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_1a ) && ( nFlagsY & DEGEN_2a ) ) {
+ newFlagsY |= DEGEN_0a;
+ newFlagsY |= DEGEN_1a;
+ newFlagsY |= DEGEN_2a;
+ }
+ if ( ( nFlagsY & DEGEN_0b ) && ( nFlagsY & DEGEN_1b ) && ( nFlagsY & DEGEN_2b ) ) {
+ newFlagsY |= DEGEN_0b;
+ newFlagsY |= DEGEN_1b;
+ newFlagsY |= DEGEN_2b;
+ }
+
+
+ //if((nFlagsX & DEGEN_0a) && (nFlagsX & DEGEN_1a) && (nFlagsX & DEGEN_2a)) { newFlagsX |= DEGEN_0a; newFlagsX |= DEGEN_1a; newFlagsX |= DEGEN_2a; }
+ //if((nFlagsX & DEGEN_0b) && (nFlagsX & DEGEN_1b) && (nFlagsX & DEGEN_2b)) { newFlagsX |= DEGEN_0b; newFlagsX |= DEGEN_1b; newFlagsX |= DEGEN_2b; }
+
+ newFlagsX |= ( nFlagsX & SPLIT );
+ newFlagsX |= ( nFlagsX & AVERAGE );
+
+ if ( !BezierCurveTree_isLeaf( BY ) ) {
+ {
+ int nTemp = newFlagsY;
+
+ if ( ( nFlagsY & DEGEN_0a ) && ( nFlagsY & DEGEN_0b ) ) {
+ newFlagsY |= DEGEN_0a;
+ newFlagsY |= DEGEN_0b;
+ }
+ newFlagsY |= ( nFlagsY & SPLIT );
+ newFlagsY |= ( nFlagsY & AVERAGE );
+
+ Vector3& p = vertex_for_index( m_tess.m_vertices, BX->index + BY->index );
+ Vector3 vTemp( p );
+
+ Vector2& p2 = texcoord_for_index( m_tess.m_vertices, BX->index + BY->index );
+ Vector2 stTemp( p2 );
+
+ TesselateSubMatrix( BY, BX->left,
+ offStartY, offStartX,
+ offEndY, BX->index,
+ newFlagsY, newFlagsX,
+ vertex_0_0, vertex_1_0, vertex_2_0,
+ texcoord_0_0, texcoord_1_0, texcoord_2_0,
+ !bTranspose );
+
+ newFlagsY = nTemp;
+ p = vTemp;
+ p2 = stTemp;
+ }
+
+ if ( ( nFlagsY & DEGEN_2a ) && ( nFlagsY & DEGEN_2b ) ) {
+ newFlagsY |= DEGEN_2a; newFlagsY |= DEGEN_2b;
+ }
+
+ TesselateSubMatrix( BY, BX->right,
+ offStartY, BX->index,
+ offEndY, offEndX,
+ newFlagsY, newFlagsX,
+ vertex_0_1, vertex_1_1, vertex_2_1,
+ texcoord_0_1, texcoord_1_1, texcoord_2_1,
+ !bTranspose );
+ }
+ else
+ {
+ if ( !BezierCurveTree_isLeaf( BX->left ) ) {
+ TesselateSubMatrix( BX->left, BY,
+ offStartX, offStartY,
+ BX->index, offEndY,
+ newFlagsX, newFlagsY,
+ left, vertex_1_0, tmp,
+ texLeft, texcoord_1_0, texTmp,
+ bTranspose );
+ }
+
+ if ( !BezierCurveTree_isLeaf( BX->right ) ) {
+ TesselateSubMatrix( BX->right, BY,
+ BX->index, offStartY,
+ offEndX, offEndY,
+ newFlagsX, newFlagsY,
+ tmp, vertex_1_1, right,
+ texTmp, texcoord_1_1, texRight,
+ bTranspose );
+ }
+ }
+
+}
+
+void Patch::BuildTesselationCurves( EMatrixMajor major ){
+ std::size_t nArrayStride, length, cross, strideU, strideV;
+ switch ( major )
+ {
+ case ROW:
+ nArrayStride = 1;
+ length = ( m_width - 1 ) >> 1;
+ cross = m_height;
+ strideU = 1;
+ strideV = m_width;
+
+ if ( !m_patchDef3 ) {
+ BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeU );
+ }
+
+ break;
+ case COL:
+ nArrayStride = m_tess.m_nArrayWidth;
+ length = ( m_height - 1 ) >> 1;
+ cross = m_width;
+ strideU = m_width;
+ strideV = 1;
+
+ if ( !m_patchDef3 ) {
+ BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeV );
+ }
+
+ break;
+ default:
+ ERROR_MESSAGE( "neither row-major nor column-major" );
+ return;
+ }
+
+ Array<std::size_t> arrayLength( length );
+ Array<BezierCurveTree*> pCurveTree( length );
+
+ std::size_t nArrayLength = 1;
+
+ if ( m_patchDef3 ) {
+ for ( Array<std::size_t>::iterator i = arrayLength.begin(); i != arrayLength.end(); ++i )
+ {
+ *i = Array<std::size_t>::value_type( ( major == ROW ) ? m_subdivisions_x : m_subdivisions_y );
+ nArrayLength += *i;
+ }
+ }
+ else
+ {
+ // create a list of the horizontal control curves in each column of sub-patches
+ // adaptively tesselate each horizontal control curve in the list
+ // create a binary tree representing the combined tesselation of the list
+ for ( std::size_t i = 0; i != length; ++i )
+ {
+ PatchControl* p1 = m_ctrlTransformed.data() + ( i * 2 * strideU );
+ GSList* pCurveList = 0;
+ for ( std::size_t j = 0; j < cross; j += 2 )
+ {
+ PatchControl* p2 = p1 + strideV;
+ PatchControl* p3 = p2 + strideV;
+
+ // directly taken from one row of control points
+ {
+ BezierCurve* pCurve = new BezierCurve;
+ pCurve->crd = ( p1 + strideU )->m_vertex;
+ pCurve->left = p1->m_vertex;
+ pCurve->right = ( p1 + ( strideU << 1 ) )->m_vertex;
+ pCurveList = g_slist_prepend( pCurveList, pCurve );
+ }
+
+ if ( j + 2 >= cross ) {
+ break;
+ }
+
+ // interpolated from three columns of control points
+ {
+ BezierCurve* pCurve = new BezierCurve;
+ pCurve->crd = vector3_mid( ( p1 + strideU )->m_vertex, ( p3 + strideU )->m_vertex );
+ pCurve->left = vector3_mid( p1->m_vertex, p3->m_vertex );
+ pCurve->right = vector3_mid( ( p1 + ( strideU << 1 ) )->m_vertex, ( p3 + ( strideU << 1 ) )->m_vertex );
+
+ pCurve->crd = vector3_mid( pCurve->crd, ( p2 + strideU )->m_vertex );
+ pCurve->left = vector3_mid( pCurve->left, p2->m_vertex );
+ pCurve->right = vector3_mid( pCurve->right, ( p2 + ( strideU << 1 ) )->m_vertex );
+ pCurveList = g_slist_prepend( pCurveList, pCurve );
+ }
+
+ p1 = p3;
+ }
+
+ pCurveTree[i] = new BezierCurveTree;
+ BezierCurveTree_FromCurveList( pCurveTree[i], pCurveList );
+ for ( GSList* l = pCurveList; l != 0; l = g_slist_next( l ) )
+ {
+ delete static_cast<BezierCurve*>( ( *l ).data );
+ }
+ g_slist_free( pCurveList );
+
+ // set up array indices for binary tree
+ // accumulate subarray width
+ arrayLength[i] = Array<std::size_t>::value_type( BezierCurveTree_Setup( pCurveTree[i], nArrayLength, nArrayStride ) - ( nArrayLength - 1 ) );
+ // accumulate total array width
+ nArrayLength += arrayLength[i];
+ }
+ }
+
+ switch ( major )
+ {
+ case ROW:
+ m_tess.m_nArrayWidth = nArrayLength;
+ std::swap( m_tess.m_arrayWidth, arrayLength );
+
+ if ( !m_patchDef3 ) {
+ std::swap( m_tess.m_curveTreeU, pCurveTree );
+ }
+ break;
+ case COL:
+ m_tess.m_nArrayHeight = nArrayLength;
+ std::swap( m_tess.m_arrayHeight, arrayLength );
+
+ if ( !m_patchDef3 ) {
+ std::swap( m_tess.m_curveTreeV, pCurveTree );
+ }
+ break;
+ }
+}
+
+inline void vertex_assign_ctrl( ArbitraryMeshVertex& vertex, const PatchControl& ctrl ){
+ vertex.vertex = vertex3f_for_vector3( ctrl.m_vertex );
+ vertex.texcoord = texcoord2f_for_vector2( ctrl.m_texcoord );
+}
+
+inline void vertex_clear_normal( ArbitraryMeshVertex& vertex ){
+ vertex.normal = Normal3f( 0, 0, 0 );
+ vertex.tangent = Normal3f( 0, 0, 0 );
+ vertex.bitangent = Normal3f( 0, 0, 0 );
+}
+
+inline void tangents_remove_degenerate( Vector3 tangents[6], Vector2 textureTangents[6], unsigned int flags ){
+ if ( flags & DEGEN_0a ) {
+ const std::size_t i =
+ ( flags & DEGEN_0b )
+ ? ( flags & DEGEN_1a )
+ ? ( flags & DEGEN_1b )
+ ? ( flags & DEGEN_2a )
+ ? 5
+ : 4
+ : 3
+ : 2
+ : 1;
+ tangents[0] = tangents[i];
+ textureTangents[0] = textureTangents[i];
+ }
+ if ( flags & DEGEN_0b ) {
+ const std::size_t i =
+ ( flags & DEGEN_0a )
+ ? ( flags & DEGEN_1b )
+ ? ( flags & DEGEN_1a )
+ ? ( flags & DEGEN_2b )
+ ? 4
+ : 5
+ : 2
+ : 3
+ : 0;
+ tangents[1] = tangents[i];
+ textureTangents[1] = textureTangents[i];
+ }
+ if ( flags & DEGEN_2a ) {
+ const std::size_t i =
+ ( flags & DEGEN_2b )
+ ? ( flags & DEGEN_1a )
+ ? ( flags & DEGEN_1b )
+ ? ( flags & DEGEN_0a )
+ ? 1
+ : 0
+ : 3
+ : 2
+ : 5;
+ tangents[4] = tangents[i];
+ textureTangents[4] = textureTangents[i];
+ }
+ if ( flags & DEGEN_2b ) {
+ const std::size_t i =
+ ( flags & DEGEN_2a )
+ ? ( flags & DEGEN_1b )
+ ? ( flags & DEGEN_1a )
+ ? ( flags & DEGEN_0b )
+ ? 0
+ : 1
+ : 2
+ : 3
+ : 4;
+ tangents[5] = tangents[i];
+ textureTangents[5] = textureTangents[i];
+ }
+}
+
+void bestTangents00( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){
+ if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate
+ if ( !( degenerateFlags & DEGEN_1a ) ) { // if this tangent is degenerate we cannot use it
+ index0 = 2;
+ index1 = 0;
+ }
+ else if ( !( degenerateFlags & DEGEN_0b ) ) {
+ index0 = 0;
+ index1 = 1;
+ }
+ else
+ {
+ index0 = 1;
+ index1 = 0;
+ }
+ }
+ else if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate
+ if ( degenerateFlags & DEGEN_0b ) {
+ index0 = 0;
+ index1 = 1;
+ }
+ else
+ {
+ index0 = 1;
+ index1 = 0;
+ }
+ }
+}
+
+void bestTangents01( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){
+ if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate
+ if ( !( degenerateFlags & DEGEN_1a ) ) { // if this tangent is degenerate we cannot use it
+ index0 = 2;
+ index1 = 1;
+ }
+ else if ( !( degenerateFlags & DEGEN_2b ) ) {
+ index0 = 4;
+ index1 = 0;
+ }
+ else
+ {
+ index0 = 5;
+ index1 = 1;
+ }
+ }
+ else if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate
+ if ( degenerateFlags & DEGEN_2b ) {
+ index0 = 4;
+ index1 = 0;
+ }
+ else
+ {
+ index0 = 5;
+ index1 = 1;
+ }
+ }
+}
+
+void bestTangents10( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){
+ if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate
+ if ( !( degenerateFlags & DEGEN_1b ) ) { // if this tangent is degenerate we cannot use it
+ index0 = 3;
+ index1 = 4;
+ }
+ else if ( !( degenerateFlags & DEGEN_0a ) ) {
+ index0 = 1;
+ index1 = 5;
+ }
+ else
+ {
+ index0 = 0;
+ index1 = 4;
+ }
+ }
+ else if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate
+ if ( degenerateFlags & DEGEN_0a ) {
+ index0 = 1;
+ index1 = 5;
+ }
+ else
+ {
+ index0 = 0;
+ index1 = 4;
+ }
+ }
+}
+
+void bestTangents11( unsigned int degenerateFlags, double dot, double length, std::size_t& index0, std::size_t& index1 ){
+ if ( fabs( dot + length ) < 0.001 ) { // opposing direction = degenerate
+ if ( !( degenerateFlags & DEGEN_1b ) ) { // if this tangent is degenerate we cannot use it
+ index0 = 3;
+ index1 = 5;
+ }
+ else if ( !( degenerateFlags & DEGEN_2a ) ) {
+ index0 = 5;
+ index1 = 4;
+ }
+ else
+ {
+ index0 = 4;
+ index1 = 5;
+ }
+ }
+ else if ( fabs( dot - length ) < 0.001 ) { // same direction = degenerate
+ if ( degenerateFlags & DEGEN_2a ) {
+ index0 = 5;
+ index1 = 4;
+ }
+ else
+ {
+ index0 = 4;
+ index1 = 5;
+ }
+ }
+}
+
+void Patch::accumulateVertexTangentSpace( std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6], Vector2 tangentT[6], std::size_t index0, std::size_t index1 ){
+ {
+ Vector3 normal( vector3_cross( tangentX[index0], tangentY[index1] ) );
+ if ( !vector3_equal( normal, g_vector3_identity ) ) {
+ vector3_add( normal_for_index( m_tess.m_vertices, index ), vector3_normalised( normal ) );
+ }
+ }
+
+ {
+ ArbitraryMeshVertex a, b, c;
+ a.vertex = Vertex3f( 0, 0, 0 );
+ a.texcoord = TexCoord2f( 0, 0 );
+ b.vertex = vertex3f_for_vector3( tangentX[index0] );
+ b.texcoord = texcoord2f_for_vector2( tangentS[index0] );
+ c.vertex = vertex3f_for_vector3( tangentY[index1] );
+ c.texcoord = texcoord2f_for_vector2( tangentT[index1] );
+
+ Vector3 s, t;
+ ArbitraryMeshTriangle_calcTangents( a, b, c, s, t );
+ if ( !vector3_equal( s, g_vector3_identity ) ) {
+ vector3_add( tangent_for_index( m_tess.m_vertices, index ), vector3_normalised( s ) );
+ }
+ if ( !vector3_equal( t, g_vector3_identity ) ) {
+ vector3_add( bitangent_for_index( m_tess.m_vertices, index ), vector3_normalised( t ) );
+ }
+ }
+}
+
+const std::size_t PATCH_MAX_VERTEX_ARRAY = 1048576;
+
+void Patch::BuildVertexArray(){
+ const std::size_t strideU = 1;
+ const std::size_t strideV = m_width;
+
+ const std::size_t numElems = m_tess.m_nArrayWidth * m_tess.m_nArrayHeight; // total number of elements in vertex array
+
+ const bool bWidthStrips = ( m_tess.m_nArrayWidth >= m_tess.m_nArrayHeight ); // decide if horizontal strips are longer than vertical
+
+
+ // allocate vertex, normal, texcoord and primitive-index arrays
+ m_tess.m_vertices.resize( numElems );
+ m_tess.m_indices.resize( m_tess.m_nArrayWidth * 2 * ( m_tess.m_nArrayHeight - 1 ) );
+
+ // set up strip indices
+ if ( bWidthStrips ) {
+ m_tess.m_numStrips = m_tess.m_nArrayHeight - 1;
+ m_tess.m_lenStrips = m_tess.m_nArrayWidth * 2;
+
+ for ( std::size_t i = 0; i < m_tess.m_nArrayWidth; i++ )
+ {
+ for ( std::size_t j = 0; j < m_tess.m_numStrips; j++ )
+ {
+ m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2] = RenderIndex( j * m_tess.m_nArrayWidth + i );
+ m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2 + 1] = RenderIndex( ( j + 1 ) * m_tess.m_nArrayWidth + i );
+ // reverse because radiant uses CULL_FRONT
+ //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(j*m_tess.m_nArrayWidth+i);
+ //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex((j+1)*m_tess.m_nArrayWidth+i);
+ }
+ }
+ }
+ else
+ {
+ m_tess.m_numStrips = m_tess.m_nArrayWidth - 1;
+ m_tess.m_lenStrips = m_tess.m_nArrayHeight * 2;
+
+ for ( std::size_t i = 0; i < m_tess.m_nArrayHeight; i++ )
+ {
+ for ( std::size_t j = 0; j < m_tess.m_numStrips; j++ )
+ {
+ m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2] = RenderIndex( ( ( m_tess.m_nArrayHeight - 1 ) - i ) * m_tess.m_nArrayWidth + j );
+ m_tess.m_indices[( j * m_tess.m_lenStrips ) + i * 2 + 1] = RenderIndex( ( ( m_tess.m_nArrayHeight - 1 ) - i ) * m_tess.m_nArrayWidth + j + 1 );
+ // reverse because radiant uses CULL_FRONT
+ //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2+1] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j);
+ //m_tess.m_indices[(j*m_tess.m_lenStrips)+i*2] = RenderIndex(((m_tess.m_nArrayHeight-1)-i)*m_tess.m_nArrayWidth+j+1);
+
+ }
+ }
+ }
+
+ {
+ PatchControlIter pCtrl = m_ctrlTransformed.data();
+ for ( std::size_t j = 0, offStartY = 0; j + 1 < m_height; j += 2, pCtrl += ( strideU + strideV ) )
+ {
+ // set up array offsets for this sub-patch
+ const bool leafY = ( m_patchDef3 ) ? false : BezierCurveTree_isLeaf( m_tess.m_curveTreeV[j >> 1] );
+ const std::size_t offMidY = ( m_patchDef3 ) ? 0 : m_tess.m_curveTreeV[j >> 1]->index;
+ const std::size_t widthY = m_tess.m_arrayHeight[j >> 1] * m_tess.m_nArrayWidth;
+ const std::size_t offEndY = offStartY + widthY;
+
+ for ( std::size_t i = 0, offStartX = 0; i + 1 < m_width; i += 2, pCtrl += ( strideU << 1 ) )
+ {
+ const bool leafX = ( m_patchDef3 ) ? false : BezierCurveTree_isLeaf( m_tess.m_curveTreeU[i >> 1] );
+ const std::size_t offMidX = ( m_patchDef3 ) ? 0 : m_tess.m_curveTreeU[i >> 1]->index;
+ const std::size_t widthX = m_tess.m_arrayWidth[i >> 1];
+ const std::size_t offEndX = offStartX + widthX;
+
+ PatchControl *subMatrix[3][3];
+ subMatrix[0][0] = pCtrl;
+ subMatrix[0][1] = subMatrix[0][0] + strideU;
+ subMatrix[0][2] = subMatrix[0][1] + strideU;
+ subMatrix[1][0] = subMatrix[0][0] + strideV;
+ subMatrix[1][1] = subMatrix[1][0] + strideU;
+ subMatrix[1][2] = subMatrix[1][1] + strideU;
+ subMatrix[2][0] = subMatrix[1][0] + strideV;
+ subMatrix[2][1] = subMatrix[2][0] + strideU;
+ subMatrix[2][2] = subMatrix[2][1] + strideU;
+
+ // assign on-patch control points to vertex array
+ if ( i == 0 && j == 0 ) {
+ vertex_clear_normal( m_tess.m_vertices[offStartX + offStartY] );
+ }
+ vertex_assign_ctrl( m_tess.m_vertices[offStartX + offStartY], *subMatrix[0][0] );
+ if ( j == 0 ) {
+ vertex_clear_normal( m_tess.m_vertices[offEndX + offStartY] );
+ }
+ vertex_assign_ctrl( m_tess.m_vertices[offEndX + offStartY], *subMatrix[0][2] );
+ if ( i == 0 ) {
+ vertex_clear_normal( m_tess.m_vertices[offStartX + offEndY] );
+ }
+ vertex_assign_ctrl( m_tess.m_vertices[offStartX + offEndY], *subMatrix[2][0] );
+
+ vertex_clear_normal( m_tess.m_vertices[offEndX + offEndY] );
+ vertex_assign_ctrl( m_tess.m_vertices[offEndX + offEndY], *subMatrix[2][2] );
+
+ if ( !m_patchDef3 ) {
+ // assign remaining control points to vertex array
+ if ( !leafX ) {
+ vertex_assign_ctrl( m_tess.m_vertices[offMidX + offStartY], *subMatrix[0][1] );
+ vertex_assign_ctrl( m_tess.m_vertices[offMidX + offEndY], *subMatrix[2][1] );
+ }
+ if ( !leafY ) {
+ vertex_assign_ctrl( m_tess.m_vertices[offStartX + offMidY], *subMatrix[1][0] );
+ vertex_assign_ctrl( m_tess.m_vertices[offEndX + offMidY], *subMatrix[1][2] );
+
+ if ( !leafX ) {
+ vertex_assign_ctrl( m_tess.m_vertices[offMidX + offMidY], *subMatrix[1][1] );
+ }
+ }
+ }
+
+ // test all 12 edges for degeneracy
+ unsigned int nFlagsX = subarray_get_degen( pCtrl, strideU, strideV );
+ unsigned int nFlagsY = subarray_get_degen( pCtrl, strideV, strideU );
+ Vector3 tangentX[6], tangentY[6];
+ Vector2 tangentS[6], tangentT[6];
+
+ // set up tangents for each of the 12 edges if they were not degenerate
+ if ( !( nFlagsX & DEGEN_0a ) ) {
+ tangentX[0] = vector3_subtracted( subMatrix[0][1]->m_vertex, subMatrix[0][0]->m_vertex );
+ tangentS[0] = vector2_subtracted( subMatrix[0][1]->m_texcoord, subMatrix[0][0]->m_texcoord );
+ }
+ if ( !( nFlagsX & DEGEN_0b ) ) {
+ tangentX[1] = vector3_subtracted( subMatrix[0][2]->m_vertex, subMatrix[0][1]->m_vertex );
+ tangentS[1] = vector2_subtracted( subMatrix[0][2]->m_texcoord, subMatrix[0][1]->m_texcoord );
+ }
+ if ( !( nFlagsX & DEGEN_1a ) ) {
+ tangentX[2] = vector3_subtracted( subMatrix[1][1]->m_vertex, subMatrix[1][0]->m_vertex );
+ tangentS[2] = vector2_subtracted( subMatrix[1][1]->m_texcoord, subMatrix[1][0]->m_texcoord );
+ }
+ if ( !( nFlagsX & DEGEN_1b ) ) {
+ tangentX[3] = vector3_subtracted( subMatrix[1][2]->m_vertex, subMatrix[1][1]->m_vertex );
+ tangentS[3] = vector2_subtracted( subMatrix[1][2]->m_texcoord, subMatrix[1][1]->m_texcoord );
+ }
+ if ( !( nFlagsX & DEGEN_2a ) ) {
+ tangentX[4] = vector3_subtracted( subMatrix[2][1]->m_vertex, subMatrix[2][0]->m_vertex );
+ tangentS[4] = vector2_subtracted( subMatrix[2][1]->m_texcoord, subMatrix[2][0]->m_texcoord );
+ }
+ if ( !( nFlagsX & DEGEN_2b ) ) {
+ tangentX[5] = vector3_subtracted( subMatrix[2][2]->m_vertex, subMatrix[2][1]->m_vertex );
+ tangentS[5] = vector2_subtracted( subMatrix[2][2]->m_texcoord, subMatrix[2][1]->m_texcoord );
+ }
+
+ if ( !( nFlagsY & DEGEN_0a ) ) {
+ tangentY[0] = vector3_subtracted( subMatrix[1][0]->m_vertex, subMatrix[0][0]->m_vertex );
+ tangentT[0] = vector2_subtracted( subMatrix[1][0]->m_texcoord, subMatrix[0][0]->m_texcoord );
+ }
+ if ( !( nFlagsY & DEGEN_0b ) ) {
+ tangentY[1] = vector3_subtracted( subMatrix[2][0]->m_vertex, subMatrix[1][0]->m_vertex );
+ tangentT[1] = vector2_subtracted( subMatrix[2][0]->m_texcoord, subMatrix[1][0]->m_texcoord );
+ }
+ if ( !( nFlagsY & DEGEN_1a ) ) {
+ tangentY[2] = vector3_subtracted( subMatrix[1][1]->m_vertex, subMatrix[0][1]->m_vertex );
+ tangentT[2] = vector2_subtracted( subMatrix[1][1]->m_texcoord, subMatrix[0][1]->m_texcoord );
+ }
+ if ( !( nFlagsY & DEGEN_1b ) ) {
+ tangentY[3] = vector3_subtracted( subMatrix[2][1]->m_vertex, subMatrix[1][1]->m_vertex );
+ tangentT[3] = vector2_subtracted( subMatrix[2][1]->m_texcoord, subMatrix[1][1]->m_texcoord );
+ }
+ if ( !( nFlagsY & DEGEN_2a ) ) {
+ tangentY[4] = vector3_subtracted( subMatrix[1][2]->m_vertex, subMatrix[0][2]->m_vertex );
+ tangentT[4] = vector2_subtracted( subMatrix[1][2]->m_texcoord, subMatrix[0][2]->m_texcoord );
+ }
+ if ( !( nFlagsY & DEGEN_2b ) ) {
+ tangentY[5] = vector3_subtracted( subMatrix[2][2]->m_vertex, subMatrix[1][2]->m_vertex );
+ tangentT[5] = vector2_subtracted( subMatrix[2][2]->m_texcoord, subMatrix[1][2]->m_texcoord );
+ }
+
+ // set up remaining edge tangents by borrowing the tangent from the closest parallel non-degenerate edge
+ tangents_remove_degenerate( tangentX, tangentS, nFlagsX );
+ tangents_remove_degenerate( tangentY, tangentT, nFlagsY );
+
+ {
+ // x=0, y=0
+ std::size_t index = offStartX + offStartY;
+ std::size_t index0 = 0;
+ std::size_t index1 = 0;
+
+ double dot = vector3_dot( tangentX[index0], tangentY[index1] );
+ double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] );
+
+ bestTangents00( nFlagsX, dot, length, index0, index1 );
+
+ accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 );
+ }
+
+ {
+ // x=1, y=0
+ std::size_t index = offEndX + offStartY;
+ std::size_t index0 = 1;
+ std::size_t index1 = 4;
+
+ double dot = vector3_dot( tangentX[index0],tangentY[index1] );
+ double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] );
+
+ bestTangents10( nFlagsX, dot, length, index0, index1 );
+
+ accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 );
+ }
+
+ {
+ // x=0, y=1
+ std::size_t index = offStartX + offEndY;
+ std::size_t index0 = 4;
+ std::size_t index1 = 1;
+
+ double dot = vector3_dot( tangentX[index0], tangentY[index1] );
+ double length = vector3_length( tangentX[index1] ) * vector3_length( tangentY[index1] );
+
+ bestTangents01( nFlagsX, dot, length, index0, index1 );
+
+ accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 );
+ }
+
+ {
+ // x=1, y=1
+ std::size_t index = offEndX + offEndY;
+ std::size_t index0 = 5;
+ std::size_t index1 = 5;
+
+ double dot = vector3_dot( tangentX[index0],tangentY[index1] );
+ double length = vector3_length( tangentX[index0] ) * vector3_length( tangentY[index1] );
+
+ bestTangents11( nFlagsX, dot, length, index0, index1 );
+
+ accumulateVertexTangentSpace( index, tangentX, tangentY, tangentS, tangentT, index0, index1 );
+ }
+
+ //normalise normals that won't be accumulated again
+ if ( i != 0 || j != 0 ) {
+ normalise_safe( normal_for_index( m_tess.m_vertices, offStartX + offStartY ) );
+ normalise_safe( tangent_for_index( m_tess.m_vertices, offStartX + offStartY ) );
+ normalise_safe( bitangent_for_index( m_tess.m_vertices, offStartX + offStartY ) );
+ }
+ if ( i + 3 == m_width ) {
+ normalise_safe( normal_for_index( m_tess.m_vertices, offEndX + offStartY ) );
+ normalise_safe( tangent_for_index( m_tess.m_vertices, offEndX + offStartY ) );
+ normalise_safe( bitangent_for_index( m_tess.m_vertices, offEndX + offStartY ) );
+ }
+ if ( j + 3 == m_height ) {
+ normalise_safe( normal_for_index( m_tess.m_vertices, offStartX + offEndY ) );
+ normalise_safe( tangent_for_index( m_tess.m_vertices, offStartX + offEndY ) );
+ normalise_safe( bitangent_for_index( m_tess.m_vertices, offStartX + offEndY ) );
+ }
+ if ( i + 3 == m_width && j + 3 == m_height ) {
+ normalise_safe( normal_for_index( m_tess.m_vertices, offEndX + offEndY ) );
+ normalise_safe( tangent_for_index( m_tess.m_vertices, offEndX + offEndY ) );
+ normalise_safe( bitangent_for_index( m_tess.m_vertices, offEndX + offEndY ) );
+ }
+
+ // set flags to average normals between shared edges
+ if ( j != 0 ) {
+ nFlagsX |= AVERAGE;
+ }
+ if ( i != 0 ) {
+ nFlagsY |= AVERAGE;
+ }
+ // set flags to save evaluating shared edges twice
+ nFlagsX |= SPLIT;
+ nFlagsY |= SPLIT;
+
+ // if the patch is curved.. tesselate recursively
+ // use the relevant control curves for this sub-patch
+ if ( m_patchDef3 ) {
+ TesselateSubMatrixFixed( m_tess.m_vertices.data() + offStartX + offStartY, 1, m_tess.m_nArrayWidth, nFlagsX, nFlagsY, subMatrix );
+ }
+ else
+ {
+ if ( !leafX ) {
+ TesselateSubMatrix( m_tess.m_curveTreeU[i >> 1], m_tess.m_curveTreeV[j >> 1],
+ offStartX, offStartY, offEndX, offEndY, // array offsets
+ nFlagsX, nFlagsY,
+ subMatrix[1][0]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[1][2]->m_vertex,
+ subMatrix[1][0]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[1][2]->m_texcoord,
+ false );
+ }
+ else if ( !leafY ) {
+ TesselateSubMatrix( m_tess.m_curveTreeV[j >> 1], m_tess.m_curveTreeU[i >> 1],
+ offStartY, offStartX, offEndY, offEndX, // array offsets
+ nFlagsY, nFlagsX,
+ subMatrix[0][1]->m_vertex, subMatrix[1][1]->m_vertex, subMatrix[2][1]->m_vertex,
+ subMatrix[0][1]->m_texcoord, subMatrix[1][1]->m_texcoord, subMatrix[2][1]->m_texcoord,
+ true );
+ }
+ }
+
+ offStartX = offEndX;
+ }
+ offStartY = offEndY;
+ }
+ }