-void Patch::InsertPoints(EMatrixMajor mt, bool bFirst)
-{
- std::size_t width, height, row_stride, col_stride;
-
- switch(mt)
- {
- case ROW:
- col_stride = 1;
- row_stride = m_width;
- width = m_width;
- height = m_height;
- break;
- case COL:
- col_stride = m_width;
- row_stride = 1;
- width = m_height;
- height = m_width;
- break;
- default:
- ERROR_MESSAGE("neither row-major nor column-major");
- return;
- }
-
- std::size_t pos = 0;
- {
- PatchControl* p1 = m_ctrl.data();
- for(std::size_t w = 0; w != width; ++w, p1 += col_stride)
- {
- {
- PatchControl* p2 = p1;
- for(std::size_t h = 1; h < height; h += 2, p2 += 2 * row_stride)
- {
- if(0)//p2->m_selectable.isSelected())
- {
- pos = h;
- 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(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(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 == 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();
+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);
+
+ int i, j;
+ float f = 1 / cos( M_PI / n );
+ for ( i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n; // 0 to 2pi
+ float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ for ( j = 0; j < height; ++j )
+ {
+ float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eXactCone ) {
+ int n = ( width - 1 ) / 2; // n = number of segments
+ setDims( width, height );
+
+ // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
+ // vPos[1] = aabb.origin;
+ // vPos[2] = vector3_added(aabb.origin, aabb.extents);
+
+ int i, j;
+ float f = 1 / cos( M_PI / n );
+ for ( i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n;
+ for ( j = 0; j < height; ++j )
+ {
+ float x = vPos[1][0] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][0] - vPos[1][0] ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( 1.0f - ( j / (float)( height - 1 ) ) ) * ( vPos[2][1] - vPos[1][1] ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float z = vPos[0][2] + ( vPos[2][2] - vPos[0][2] ) * ( j / (float)( height - 1 ) );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eXactSphere ) {
+ int n = ( width - 1 ) / 2; // n = number of segments (yaw)
+ int m = ( height - 1 ) / 2; // m = number of segments (pitch)
+ setDims( width, height );
+
+ // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents);
+ // vPos[1] = aabb.origin;
+ // vPos[2] = vector3_added(aabb.origin, aabb.extents);
+
+ int i, j;
+ float f = 1 / cos( M_PI / n );
+ float g = 1 / cos( M_PI / ( 2 * m ) );
+ for ( i = 0; i < width; ++i )
+ {
+ float angle = ( M_PI * i ) / n;
+ for ( j = 0; j < height; ++j )
+ {
+ float angle2 = ( M_PI * j ) / ( 2 * m );
+ float x = vPos[1][0] + ( vPos[2][0] - vPos[1][0] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * cos( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float y = vPos[1][1] + ( vPos[2][1] - vPos[1][1] ) * sin( angle2 ) * ( ( j & 1 ) ? g : 1.0f ) * sin( angle ) * ( ( i & 1 ) ? f : 1.0f );
+ float z = vPos[1][2] + ( vPos[2][2] - vPos[1][2] ) * -cos( angle2 ) * ( ( j & 1 ) ? g : 1.0f );
+ PatchControl *v;
+ v = &m_ctrl.data()[j * width + i];
+ v->m_vertex[0] = x;
+ v->m_vertex[1] = y;
+ v->m_vertex[2] = z;
+ }
+ }
+ }
+ else if ( eType == eBevel ) {
+ unsigned char *pIndex;
+ unsigned char pBevIndex[] =
+ {
+ 0, 0,
+ 2, 0,
+ 2, 2,
+ };
+
+ setDims( 3, 3 );
+
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++ )
+ {
+ pIndex = pBevIndex;
+ for ( std::size_t w = 0; w < 3; w++, pIndex += 2, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
+ pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
+ pCtrl->m_vertex[2] = vPos[h][2];
+ }
+ }
+ }
+ else if ( eType == eEndCap ) {
+ unsigned char *pIndex;
+ unsigned char pEndIndex[] =
+ {
+ 2, 0,
+ 2, 2,
+ 1, 2,
+ 0, 2,
+ 0, 0,
+ };
+
+ setDims( 5, 3 );
+
+ PatchControl* pCtrl = m_ctrl.data();
+ for ( std::size_t h = 0; h < 3; h++ )
+ {
+ pIndex = pEndIndex;
+ for ( std::size_t w = 0; w < 5; w++, pIndex += 2, pCtrl++ )
+ {
+ pCtrl->m_vertex[0] = vPos[pIndex[0]][0];
+ pCtrl->m_vertex[1] = vPos[pIndex[1]][1];
+ pCtrl->m_vertex[2] = vPos[h][2];
+ }
+ }
+ }
+
+ if ( eType == eDenseCylinder ) {
+ InsertRemove( true, false, true );
+ }
+
+ if ( eType == eVeryDenseCylinder ) {
+ InsertRemove( true, false, false );
+ InsertRemove( true, false, true );
+ }
+
+ NaturalTexture();
+}
+
+void Patch::RenderDebug( RenderStateFlags state ) const {
+ for ( std::size_t i = 0; i < m_tess.m_numStrips; i++ )
+ {
+ glBegin( GL_QUAD_STRIP );
+ for ( std::size_t j = 0; j < m_tess.m_lenStrips; j++ )
+ {
+ glNormal3fv( normal3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->normal ) );
+ glTexCoord2fv( texcoord2f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->texcoord ) );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + m_tess.m_indices[i * m_tess.m_lenStrips + j] )->vertex ) );
+ }
+ glEnd();
+ }
+}
+
+void RenderablePatchSolid::RenderNormals() const {
+ const std::size_t width = m_tess.m_numStrips + 1;
+ const std::size_t height = m_tess.m_lenStrips >> 1;
+ glBegin( GL_LINES );
+ for ( std::size_t i = 0; i < width; i++ )
+ {
+ for ( std::size_t j = 0; j < height; j++ )
+ {
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->normal ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->tangent ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ {
+ Vector3 vNormal(
+ vector3_added(
+ vertex3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ),
+ vector3_scaled( normal3f_to_vector3( ( m_tess.m_vertices.data() + ( j * width + i ) )->bitangent ), 8 )
+ )
+ );
+ glVertex3fv( vertex3f_to_array( ( m_tess.m_vertices.data() + ( j * width + i ) )->vertex ) );
+ glVertex3fv( &vNormal[0] );
+ }
+ }
+ }
+ glEnd();