+void Patch::AccumulateBBox(){
+ m_aabb_local = AABB();
+
+ for ( PatchControlArray::iterator i = m_ctrlTransformed.begin(); i != m_ctrlTransformed.end(); ++i )
+ {
+ aabb_extend_by_point_safe( m_aabb_local, ( *i ).m_vertex );
+ }
+
+ m_boundsChanged();
+ m_lightsChanged();
+}
+
+void Patch::InsertPoints( EMatrixMajor mt, bool bFirst ){
+ std::size_t width, height, row_stride, col_stride;
+
+ switch ( mt )
+ {
+ case ROW:
+ col_stride = 1;
+ row_stride = m_width;
+ width = m_width;
+ height = m_height;
+ break;
+ case COL:
+ col_stride = m_width;
+ row_stride = 1;
+ width = m_height;
+ height = m_width;
+ break;
+ default:
+ ERROR_MESSAGE( "neither row-major nor column-major" );
+ return;
+ }
+
+ std::size_t pos = 0;
+ {
+ PatchControl* p1 = m_ctrl.data();
+ /*
+ if(GlobalSelectionSystem().countSelected() != 0)
+ {
+ scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
+ PatchInstance* patch = Instance_getPatch(instance);
+ patch->m_selectable.isSelected();
+ }
+ */
+ for ( std::size_t w = 0; w != width; ++w, p1 += col_stride )
+ {
+ {
+ PatchControl* p2 = p1;
+ for ( std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride )
+ {
+ if ( 0 ) { //p2->m_selectable.isSelected())
+ pos = h;
+ break;
+ }
+ }
+ if ( pos != 0 ) {
+ break;
+ }
+ }
+
+ {
+ PatchControl* p2 = p1;
+ for ( std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride )
+ {
+ if ( 0 ) { //p2->m_selectable.isSelected())
+ pos = h;
+ break;
+ }
+ }
+ if ( pos != 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ Array<PatchControl> tmp( m_ctrl );
+
+ std::size_t row_stride2, col_stride2;
+ switch ( mt )
+ {
+ case ROW:
+ setDims( m_width, m_height + 2 );
+ col_stride2 = 1;
+ row_stride2 = m_width;
+ break;
+ case COL:
+ setDims( m_width + 2, m_height );
+ col_stride2 = m_width;
+ row_stride2 = 1;
+ break;
+ default:
+ ERROR_MESSAGE( "neither row-major nor column-major" );
+ return;
+ }
+ if ( bFirst ) {
+ pos = height - 1;
+ }
+ else
+ {
+ pos = 2;
+ }
+
+ if ( pos >= height ) {
+ if ( bFirst ) {
+ pos = height - 1;
+ }
+ else
+ {
+ pos = 2;
+ }
+ }
+ else if ( pos == 0 ) {
+ pos = 2;
+ }
+ else if ( pos % 2 ) {
+ ++pos;
+ }
+
+
+ for ( std::size_t w = 0; w != width; ++w )
+ {
+ PatchControl* p1 = tmp.data() + ( w * col_stride );
+ PatchControl* p2 = m_ctrl.data() + ( w * col_stride2 );
+ for ( std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride )
+ {
+ if ( h == pos ) {
+ p2 += 2 * row_stride2;
+ }
+ *p2 = *p1;
+ }
+
+ p1 = tmp.data() + ( w * col_stride + pos * row_stride );
+ p2 = m_ctrl.data() + ( w * col_stride2 + pos * row_stride2 );
+
+ PatchControl* r2a = ( p2 + row_stride2 );
+ PatchControl* r2b = ( p2 - row_stride2 );
+ PatchControl* c2a = ( p1 - 2 * row_stride );
+ PatchControl* c2b = ( p1 - row_stride );
+
+ // set two new row points
+ *( p2 + 2 * row_stride2 ) = *p1;
+ *r2a = *c2b;
+
+ for ( std::size_t i = 0; i != 3; ++i )
+ {
+ r2a->m_vertex[i] = float_mid( c2b->m_vertex[i], p1->m_vertex[i] );
+
+ r2b->m_vertex[i] = float_mid( c2a->m_vertex[i], c2b->m_vertex[i] );
+
+ p2->m_vertex[i] = float_mid( r2a->m_vertex[i], r2b->m_vertex[i] );
+ }
+ for ( std::size_t i = 0; i != 2; ++i )
+ {
+ r2a->m_texcoord[i] = float_mid( c2b->m_texcoord[i], p1->m_texcoord[i] );
+
+ r2b->m_texcoord[i] = float_mid( c2a->m_texcoord[i], c2b->m_texcoord[i] );
+
+ p2->m_texcoord[i] = float_mid( r2a->m_texcoord[i], r2b->m_texcoord[i] );
+ }
+ }
+}
+
+void Patch::RemovePoints( EMatrixMajor mt, bool bFirst ){
+ std::size_t width, height, row_stride, col_stride;
+
+ switch ( mt )
+ {
+ case ROW:
+ col_stride = 1;
+ row_stride = m_width;
+ width = m_width;
+ height = m_height;
+ break;
+ case COL:
+ col_stride = m_width;
+ row_stride = 1;
+ width = m_height;
+ height = m_width;
+ break;
+ default:
+ ERROR_MESSAGE( "neither row-major nor column-major" );
+ return;
+ }
+
+ std::size_t pos = 0;
+ {
+ PatchControl* p1 = m_ctrl.data();
+ for ( std::size_t w = 0; w != width; ++w, p1 += col_stride )
+ {
+ {
+ PatchControl* p2 = p1;
+ for ( std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride )
+ {
+ if ( 0 ) { //p2->m_selectable.isSelected())
+ pos = h;
+ break;
+ }
+ }
+ if ( pos != 0 ) {
+ break;
+ }
+ }
+
+ {
+ PatchControl* p2 = p1;
+ for ( std::size_t h = 0; h < height; h += 2, p2 += 2 * row_stride )
+ {
+ if ( 0 ) { //p2->m_selectable.isSelected())
+ pos = h;
+ break;
+ }
+ }
+ if ( pos != 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ Array<PatchControl> tmp( m_ctrl );
+
+ std::size_t row_stride2, col_stride2;
+ switch ( mt )
+ {
+ case ROW:
+ setDims( m_width, m_height - 2 );
+ col_stride2 = 1;
+ row_stride2 = m_width;
+ break;
+ case COL:
+ setDims( m_width - 2, m_height );
+ col_stride2 = m_width;
+ row_stride2 = 1;
+ break;
+ default:
+ ERROR_MESSAGE( "neither row-major nor column-major" );
+ return;
+ }
+ if ( bFirst ) {
+ pos = height - 3;
+ }
+ else
+ {
+ pos = 2;
+ }
+ if ( pos >= height ) {
+ if ( bFirst ) {
+ pos = height - 3;
+ }
+ else
+ {
+ pos = 2;
+ }
+ }
+ else if ( pos == 0 ) {
+ pos = 2;
+ }
+ else if ( pos > height - 3 ) {
+ pos = height - 3;
+ }
+ else if ( pos % 2 ) {
+ ++pos;
+ }
+
+ for ( std::size_t w = 0; w != width; w++ )
+ {
+ PatchControl* p1 = tmp.data() + ( w * col_stride );
+ PatchControl* p2 = m_ctrl.data() + ( w * col_stride2 );
+ for ( std::size_t h = 0; h != height; ++h, p2 += row_stride2, p1 += row_stride )
+ {
+ if ( h == pos ) {
+ p1 += 2 * row_stride2; h += 2;
+ }
+ *p2 = *p1;
+ }
+
+ p1 = tmp.data() + ( w * col_stride + pos * row_stride );
+ p2 = m_ctrl.data() + ( w * col_stride2 + pos * row_stride2 );
+
+ for ( std::size_t i = 0; i < 3; i++ )
+ {
+ ( p2 - row_stride2 )->m_vertex[i] = ( ( p1 + 2 * row_stride )->m_vertex[i] + ( p1 - 2 * row_stride )->m_vertex[i] ) * 0.5f;
+
+ ( p2 - row_stride2 )->m_vertex[i] = ( p2 - row_stride2 )->m_vertex[i] + ( 2.0f * ( ( p1 )->m_vertex[i] - ( p2 - row_stride2 )->m_vertex[i] ) );
+ }
+ for ( std::size_t i = 0; i < 2; i++ )
+ {
+ ( p2 - row_stride2 )->m_texcoord[i] = ( ( p1 + 2 * row_stride )->m_texcoord[i] + ( p1 - 2 * row_stride )->m_texcoord[i] ) * 0.5f;
+
+ ( p2 - row_stride2 )->m_texcoord[i] = ( p2 - row_stride2 )->m_texcoord[i] + ( 2.0f * ( ( p1 )->m_texcoord[i] - ( p2 - row_stride2 )->m_texcoord[i] ) );
+ }
+ }
+}
+
+void Patch::ConstructSeam( EPatchCap eType, Vector3* p, std::size_t width ){
+ switch ( eType )
+ {
+ case eCapIBevel:
+ {
+ setDims( 3, 3 );
+ m_ctrl[0].m_vertex = p[0];
+ m_ctrl[1].m_vertex = p[1];
+ m_ctrl[2].m_vertex = p[1];
+ m_ctrl[3].m_vertex = p[1];
+ m_ctrl[4].m_vertex = p[1];
+ m_ctrl[5].m_vertex = p[1];
+ m_ctrl[6].m_vertex = p[2];
+ m_ctrl[7].m_vertex = p[1];
+ m_ctrl[8].m_vertex = p[1];
+ }
+ break;
+ case eCapBevel:
+ {
+ setDims( 3, 3 );
+ Vector3 p3( vector3_added( p[2], vector3_subtracted( p[0], p[1] ) ) );
+ m_ctrl[0].m_vertex = p3;
+ m_ctrl[1].m_vertex = p3;
+ m_ctrl[2].m_vertex = p[2];
+ m_ctrl[3].m_vertex = p3;
+ m_ctrl[4].m_vertex = p3;
+ m_ctrl[5].m_vertex = p[1];
+ m_ctrl[6].m_vertex = p3;
+ m_ctrl[7].m_vertex = p3;
+ m_ctrl[8].m_vertex = p[0];
+ }
+ break;
+ case eCapEndCap:
+ {
+ Vector3 p5( vector3_mid( p[0], p[4] ) );
+
+ setDims( 3, 3 );
+ m_ctrl[0].m_vertex = p[0];
+ m_ctrl[1].m_vertex = p5;
+ m_ctrl[2].m_vertex = p[4];
+ m_ctrl[3].m_vertex = p[1];
+ m_ctrl[4].m_vertex = p[2];
+ m_ctrl[5].m_vertex = p[3];
+ m_ctrl[6].m_vertex = p[2];
+ m_ctrl[7].m_vertex = p[2];
+ m_ctrl[8].m_vertex = p[2];
+ }
+ break;
+ case eCapIEndCap:
+ {
+ setDims( 5, 3 );
+ m_ctrl[0].m_vertex = p[4];
+ m_ctrl[1].m_vertex = p[3];
+ m_ctrl[2].m_vertex = p[2];
+ m_ctrl[3].m_vertex = p[1];
+ m_ctrl[4].m_vertex = p[0];
+ m_ctrl[5].m_vertex = p[3];
+ m_ctrl[6].m_vertex = p[3];
+ m_ctrl[7].m_vertex = p[2];
+ m_ctrl[8].m_vertex = p[1];
+ m_ctrl[9].m_vertex = p[1];
+ m_ctrl[10].m_vertex = p[3];
+ m_ctrl[11].m_vertex = p[3];
+ m_ctrl[12].m_vertex = p[2];
+ m_ctrl[13].m_vertex = p[1];
+ m_ctrl[14].m_vertex = p[1];
+ }
+ break;
+ case eCapCylinder:
+ {
+ std::size_t mid = ( width - 1 ) >> 1;
+
+ bool degenerate = ( mid % 2 ) != 0;
+
+ std::size_t newHeight = mid + ( degenerate ? 2 : 1 );
+
+ setDims( 3, newHeight );
+
+ if ( degenerate ) {
+ ++mid;
+ for ( std::size_t i = width; i != width + 2; ++i )
+ {
+ p[i] = p[width - 1];
+ }
+ }
+
+ {
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t i = 0; i != m_height; ++i, pCtrl += m_width )
+ {
+ pCtrl->m_vertex = p[i];
+ }
+ }
+ {
+ PatchControl* pCtrl = m_ctrl.data() + 2;
+ std::size_t h = m_height - 1;
+ for ( std::size_t i = 0; i != m_height; ++i, pCtrl += m_width )
+ {
+ pCtrl->m_vertex = p[h + ( h - i )];
+ }
+ }
+
+ Redisperse( COL );
+ }
+ break;
+ default:
+ ERROR_MESSAGE( "invalid patch-cap type" );
+ return;
+ }
+ CapTexture();
+ controlPointsChanged();
+}
+
+void Patch::ProjectTexture( int nAxis ){
+ undoSave();
+
+ int s, t;
+
+ switch ( nAxis )
+ {
+ case 2:
+ s = 0;
+ t = 1;
+ break;
+ case 0:
+ s = 1;
+ t = 2;
+ break;
+ case 1:
+ s = 0;
+ t = 2;
+ break;
+ default:
+ ERROR_MESSAGE( "invalid axis" );
+ return;
+ }
+
+ float fWidth = 1 / ( m_state->getTexture().width * Texdef_getDefaultTextureScale() );
+ float fHeight = 1 / ( m_state->getTexture().height * -Texdef_getDefaultTextureScale() );
+
+ for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i )
+ {
+ ( *i ).m_texcoord[0] = ( *i ).m_vertex[s] * fWidth;
+ ( *i ).m_texcoord[1] = ( *i ).m_vertex[t] * fHeight;
+ }
+
+ controlPointsChanged();
+}
+
+void Patch::constructPlane( const AABB& aabb, int axis, std::size_t width, std::size_t height ){
+ setDims( width, height );
+
+ int x, y, z;
+ switch ( axis )
+ {
+ case 2: x = 0; y = 1; z = 2; break;
+ case 1: x = 0; y = 2; z = 1; break;
+ case 0: x = 1; y = 2; z = 0; break;
+ default:
+ ERROR_MESSAGE( "invalid view-type" );
+ return;
+ }
+
+ if ( m_width < MIN_PATCH_WIDTH || m_width > MAX_PATCH_WIDTH ) {
+ m_width = 3;
+ }
+ if ( m_height < MIN_PATCH_HEIGHT || m_height > MAX_PATCH_HEIGHT ) {
+ m_height = 3;
+ }
+
+ Vector3 vStart;
+ vStart[x] = aabb.origin[x] - aabb.extents[x];
+ vStart[y] = aabb.origin[y] - aabb.extents[y];
+ vStart[z] = aabb.origin[z];
+
+ float xAdj = fabsf( ( vStart[x] - ( aabb.origin[x] + aabb.extents[x] ) ) / (float)( m_width - 1 ) );
+ float yAdj = fabsf( ( vStart[y] - ( aabb.origin[y] + aabb.extents[y] ) ) / (float)( m_height - 1 ) );
+
+ Vector3 vTmp;
+ vTmp[z] = vStart[z];
+ PatchControl* pCtrl = m_ctrl.data();
+
+ vTmp[y] = vStart[y];
+ for ( std::size_t h = 0; h < m_height; h++ )
+ {
+ vTmp[x] = vStart[x];
+ for ( std::size_t w = 0; w < m_width; w++, ++pCtrl )
+ {
+ pCtrl->m_vertex = vTmp;
+ vTmp[x] += xAdj;
+ }
+ vTmp[y] += yAdj;
+ }
+
+ NaturalTexture();
+}
+
+void Patch::ConstructPrefab( const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width, std::size_t height ){
+ Vector3 vPos[3];
+
+ if ( eType != ePlane ) {
+ vPos[0] = vector3_subtracted( aabb.origin, aabb.extents );
+ vPos[1] = aabb.origin;
+ vPos[2] = vector3_added( aabb.origin, aabb.extents );
+ }
+
+ if ( eType == ePlane ) {
+ constructPlane( aabb, axis, width, height );
+ }
+ else if ( eType == eSqCylinder
+ || eType == eCylinder
+ || eType == eDenseCylinder
+ || eType == eVeryDenseCylinder
+ || eType == eCone
+ || eType == eSphere ) {
+ unsigned char *pIndex;
+ unsigned char pCylIndex[] =
+ {
+ 0, 0,
+ 1, 0,
+ 2, 0,
+ 2, 1,
+ 2, 2,
+ 1, 2,
+ 0, 2,
+ 0, 1,
+ 0, 0
+ };
+
+
+ PatchControl *pStart;
+ switch ( eType )
+ {
+ case eSqCylinder: setDims( 9, 3 );
+ pStart = m_ctrl.data();
+ break;
+ case eDenseCylinder:
+ case eVeryDenseCylinder:
+ case eCylinder:
+ setDims( 9, 3 );
+ pStart = m_ctrl.data() + 1;
+ break;
+ case eCone: setDims( 9, 3 );
+ pStart = m_ctrl.data() + 1;
+ break;
+ case eSphere:
+ setDims( 9, 5 );
+ pStart = m_ctrl.data() + ( 9 + 1 );
+ break;
+ default:
+ ERROR_MESSAGE( "this should be unreachable" );
+ return;
+ }
+
+ for ( std::size_t h = 0; h < 3; h++, pStart += 9 )
+ {
+ pIndex = pCylIndex;
+ PatchControl* pCtrl = pStart;
+ for ( std::size_t w = 0; w < 8; w++, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
+ pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
+ pCtrl->m_vertex[2] = vPos[h][2];
+ pIndex += 2;
+ }
+ }
+
+ switch ( eType )
+ {
+ case eSqCylinder:
+ {
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 )
+ {
+ pCtrl[8].m_vertex = pCtrl[0].m_vertex;
+ }
+ }
+ break;
+ case eDenseCylinder:
+ case eVeryDenseCylinder:
+ case eCylinder:
+ {
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 )
+ {
+ pCtrl[0].m_vertex = pCtrl[8].m_vertex;
+ }
+ }
+ break;
+ case eCone:
+ {
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 2; h++, pCtrl += 9 )
+ {
+ pCtrl[0].m_vertex = pCtrl[8].m_vertex;
+ }
+ }
+ {
+ PatchControl* pCtrl = m_ctrl.data() + 9 * 2;
+ for ( std::size_t w = 0; w < 9; w++, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[1][0];
+ pCtrl->m_vertex[1] = vPos[1][1];
+ pCtrl->m_vertex[2] = vPos[2][2];
+ }
+ }
+ break;
+ case eSphere:
+ {
+ PatchControl* pCtrl = m_ctrl.data() + 9;
+ for ( std::size_t h = 0; h < 3; h++, pCtrl += 9 )
+ {
+ pCtrl[0].m_vertex = pCtrl[8].m_vertex;
+ }
+ }
+ {
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t w = 0; w < 9; w++, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[1][0];
+ pCtrl->m_vertex[1] = vPos[1][1];
+ pCtrl->m_vertex[2] = vPos[0][2];
+ }
+ }
+ {
+ PatchControl* pCtrl = m_ctrl.data() + ( 9 * 4 );
+ for ( std::size_t w = 0; w < 9; w++, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[1][0];
+ pCtrl->m_vertex[1] = vPos[1][1];
+ pCtrl->m_vertex[2] = vPos[2][2];
+ }
+ }
+ break;
+ default:
+ ERROR_MESSAGE( "this should be unreachable" );
+ return;
+ }
+ }
+ else if ( eType == eXactCylinder ) {
+ int n = ( width - 1 ) / 2; // n = number of segments
+ setDims( width, height );
+
+ // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
+ // vPos[1] = aabb.origin;
+ // vPos[2] = vector3_added(aabb.origin, aabb.extents);
+
+ float f = 1 / cos( M_PI / n );
+ for ( std::size_t i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n; // 0 to 2pi
+ float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ for ( std::size_t j = 0; j < height; ++j )
+ {
+ float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eXactCone ) {
+ int n = ( width - 1 ) / 2; // n = number of segments
+ setDims( width, height );
+
+ // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
+ // vPos[1] = aabb.origin;
+ // vPos[2] = vector3_added(aabb.origin, aabb.extents);
+
+ float f = 1 / cos( M_PI / n );
+ for ( std::size_t i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n;
+ for ( std::size_t j = 0; j < height; ++j )
+ {
+ float x = vPos[1][0] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eXactSphere ) {
+ int n = ( width - 1 ) / 2; // n = number of segments (yaw)
+ int m = ( height - 1 ) / 2; // m = number of segments (pitch)
+ setDims( width, height );
+
+ // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
+ // vPos[1] = aabb.origin;
+ // vPos[2] = vector3_added(aabb.origin, aabb.extents);
+
+ float f = 1 / cos( M_PI / n );
+ float g = 1 / cos( M_PI / ( 2 * m ) );
+ for ( std::size_t i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n;
+ for ( std::size_t j = 0; j < height; ++j )
+ {
+ float angle2 = ( M_PI * j ) / ( 2 * m );
+ float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float z = vPos[1][2] + ( vPos[2][2] - vPos[1][2] ) * -cos( angle2 ) * ( ( j & 1 ) ? g : 1.0f );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eBevel ) {
+ unsigned char *pIndex;
+ unsigned char pBevIndex[] =
+ {
+ 0, 0,
+ 2, 0,
+ 2, 2,
+ };
+
+ setDims( 3, 3 );
+
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++ )
+ {
+ pIndex = pBevIndex;
+ for ( std::size_t w = 0; w < 3; w++, pIndex += 2, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
+ pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
+ pCtrl->m_vertex[2] = vPos[h][2];
+ }
+ }
+ }
+ else if ( eType == eEndCap ) {
+ unsigned char *pIndex;
+ unsigned char pEndIndex[] =
+ {
+ 2, 0,
+ 2, 2,
+ 1, 2,
+ 0, 2,
+ 0, 0,
+ };
+
+ setDims( 5, 3 );
+
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++ )
+ {
+ pIndex = pEndIndex;
+ for ( std::size_t w = 0; w < 5; w++, pIndex += 2, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
+ pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
+ pCtrl->m_vertex[2] = vPos[h][2];
+ }
+ }
+ }
+
+ if ( eType == eDenseCylinder ) {
+ InsertRemove( true, false, true );
+ }
+
+ if ( eType == eVeryDenseCylinder ) {
+ InsertRemove( true, false, false );
+ InsertRemove( true, false, true );
+ }
+
+ NaturalTexture();
+}
+
+void Patch::RenderDebug( RenderStateFlags state ) const {
+ for ( std::size_t i = 0; i < m_tess.m_numStrips; i++ )
+ {
+ glBegin( GL_QUAD_STRIP );
+ for ( std::size_t j = 0; j < m_tess.m_lenStrips; j++ )
+ {
+ glNormal3fv( normal3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->normal ) );
+ glTexCoord2fv( texcoord2f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->texcoord ) );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->vertex ) );
+ }
+ glEnd();
+ }
+}
+
+void RenderablePatchSolid::RenderNormals() const {
+ const std::size_t width = m_tess.m_numStrips + 1;
+ const std::size_t height = m_tess.m_lenStrips >> 1;
+ glBegin( GL_LINES );
+ for ( std::size_t i = 0; i < width; i++ )
+ {
+ for ( std::size_t j = 0; j < height; j++ )
+ {
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->normal ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->tangent ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->bitangent ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ }
+ }
+ glEnd();
+}
+
+const int DEGEN_0a = 0x01;
+const int DEGEN_1a = 0x02;
+const int DEGEN_2a = 0x04;
+const int DEGEN_0b = 0x08;
+const int DEGEN_1b = 0x10;
+const int DEGEN_2b = 0x20;
+const int SPLIT = 0x40;
+const int AVERAGE = 0x80;
+
+
+unsigned int subarray_get_degen( PatchControlIter subarray, std::size_t strideU, std::size_t strideV ){
+ unsigned int nDegen = 0;
+ const PatchControl* p1;
+ const PatchControl* p2;
+
+ p1 = subarray;
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_0a;
+ }
+ p1 = p2;
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_0b;
+ }
+
+ p1 = subarray + strideV;
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_1a;
+ }
+ p1 = p2;
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_1b;
+ }
+
+ p1 = subarray + ( strideV << 1 );
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_2a;
+ }
+ p1 = p2;
+ p2 = p1 + strideU;
+ if ( vector3_equal( p1->m_vertex, p2->m_vertex ) ) {
+ nDegen |= DEGEN_2b;
+ }
+
+ return nDegen;
+}
+