//-------------------------------------------------------------------------------------------------------------- //获取该矢量的长度 float Vector2::GetLength() const { return Vec2Length( this ); }
/* draw a given stroke in 2d */ static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int offsx, int offsy, int winx, int winy) { /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better * - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke */ if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) ) { bGPDspoint *pt; int i; glBegin(GL_LINE_STRIP); for (i=0, pt=points; i < totpoints && pt; i++, pt++) { if (sflag & GP_STROKE_2DSPACE) { glVertex2f(pt->x, pt->y); } else if (sflag & GP_STROKE_2DIMAGE) { const float x= (pt->x * winx) + offsx; const float y= (pt->y * winy) + offsy; glVertex2f(x, y); } else { const float x= (pt->x / 100 * winx); const float y= (pt->y / 100 * winy); glVertex2f(x, y); } } glEnd(); } /* tesselation code - draw stroke as series of connected quads with connection * edges rotated to minimise shrinking artifacts, and rounded endcaps */ else { bGPDspoint *pt1, *pt2; float pm[2]; int i; glShadeModel(GL_FLAT); glBegin(GL_QUADS); for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) { float s0[2], s1[2]; /* segment 'center' points */ float t0[2], t1[2]; /* tesselated coordinates */ float m1[2], m2[2]; /* gradient and normal */ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */ float pthick; /* thickness at segment point */ /* get x and y coordinates from points */ if (sflag & GP_STROKE_2DSPACE) { s0[0]= pt1->x; s0[1]= pt1->y; s1[0]= pt2->x; s1[1]= pt2->y; } else if (sflag & GP_STROKE_2DIMAGE) { s0[0]= (pt1->x * winx) + offsx; s0[1]= (pt1->y * winy) + offsy; s1[0]= (pt2->x * winx) + offsx; s1[1]= (pt2->y * winy) + offsy; } else { s0[0]= (pt1->x / 100 * winx); s0[1]= (pt1->y / 100 * winy); s1[0]= (pt2->x / 100 * winx); s1[1]= (pt2->y / 100 * winy); } /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1]= s1[1] - s0[1]; m1[0]= s1[0] - s0[0]; Normalize2(m1); m2[1]= -m1[0]; m2[0]= m1[1]; /* always use pressure from first point here */ pthick= (pt1->pressure * thickness); /* if the first segment, start of segment is segment's normal */ if (i == 0) { /* draw start cap first * - make points slightly closer to center (about halfway across) */ mt[0]= m2[0] * pthick * 0.5f; mt[1]= m2[1] * pthick * 0.5f; sc[0]= s0[0] - (m1[0] * pthick * 0.75f); sc[1]= s0[1] - (m1[1] * pthick * 0.75f); t0[0]= sc[0] - mt[0]; t0[1]= sc[1] - mt[1]; t1[0]= sc[0] + mt[0]; t1[1]= sc[1] + mt[1]; glVertex2fv(t0); glVertex2fv(t1); /* calculate points for start of segment */ mt[0]= m2[0] * pthick; mt[1]= m2[1] * pthick; t0[0]= s0[0] - mt[0]; t0[1]= s0[1] - mt[1]; t1[0]= s0[0] + mt[0]; t1[1]= s0[1] + mt[1]; /* draw this line twice (first to finish off start cap, then for stroke) */ glVertex2fv(t1); glVertex2fv(t0); glVertex2fv(t0); glVertex2fv(t1); } /* if not the first segment, use bisector of angle between segments */ else { float mb[2]; /* bisector normal */ float athick, dfac; /* actual thickness, difference between thicknesses */ /* calculate gradient of bisector (as average of normals) */ mb[0]= (pm[0] + m2[0]) / 2; mb[1]= (pm[1] + m2[1]) / 2; Normalize2(mb); /* calculate gradient to apply * - as basis, use just pthick * bisector gradient * - if cross-section not as thick as it should be, add extra padding to fix it */ mt[0]= mb[0] * pthick; mt[1]= mb[1] * pthick; athick= Vec2Length(mt); dfac= pthick - (athick * 2); if ( ((athick * 2) < pthick) && (IS_EQ(athick, pthick)==0) ) { mt[0] += (mb[0] * dfac); mt[1] += (mb[1] * dfac); } /* calculate points for start of segment */ t0[0]= s0[0] - mt[0]; t0[1]= s0[1] - mt[1]; t1[0]= s0[0] + mt[0]; t1[1]= s0[1] + mt[1]; /* draw this line twice (once for end of current segment, and once for start of next) */ glVertex2fv(t1); glVertex2fv(t0); glVertex2fv(t0); glVertex2fv(t1); } /* if last segment, also draw end of segment (defined as segment's normal) */ if (i == totpoints-2) { /* for once, we use second point's pressure (otherwise it won't be drawn) */ pthick= (pt2->pressure * thickness); /* calculate points for end of segment */ mt[0]= m2[0] * pthick; mt[1]= m2[1] * pthick; t0[0]= s1[0] - mt[0]; t0[1]= s1[1] - mt[1]; t1[0]= s1[0] + mt[0]; t1[1]= s1[1] + mt[1]; /* draw this line twice (once for end of stroke, and once for endcap)*/ glVertex2fv(t1); glVertex2fv(t0); glVertex2fv(t0); glVertex2fv(t1); /* draw end cap as last step * - make points slightly closer to center (about halfway across) */ mt[0]= m2[0] * pthick * 0.5f; mt[1]= m2[1] * pthick * 0.5f; sc[0]= s1[0] + (m1[0] * pthick * 0.75f); sc[1]= s1[1] + (m1[1] * pthick * 0.75f); t0[0]= sc[0] - mt[0]; t0[1]= sc[1] - mt[1]; t1[0]= sc[0] + mt[0]; t1[1]= sc[1] + mt[1]; glVertex2fv(t1); glVertex2fv(t0); } /* store stroke's 'natural' normal for next stroke to use */ Vec2Copyf(pm, m2); } glEnd(); } /* draw debug points of curve on top? (original stroke points) */ if (debug) { bGPDspoint *pt; int i; glBegin(GL_POINTS); for (i=0, pt=points; i < totpoints && pt; i++, pt++) { if (sflag & GP_STROKE_2DSPACE) { glVertex2f(pt->x, pt->y); } else if (sflag & GP_STROKE_2DIMAGE) { const float x= (float)((pt->x * winx) + offsx); const float y= (float)((pt->y * winy) + offsy); glVertex2f(x, y); } else { const float x= (float)(pt->x / 100 * winx); const float y= (float)(pt->y / 100 * winy); glVertex2f(x, y); } } glEnd(); } }
void MeshParameterization::GenerateTriangleTexelData() { #if ENABLE_DEBUG_DEGENERATES map< float, blah > s_DegenerateList; #endif //Generate texel data per triangle const float uIncrement = 1.f/(float)m_TexSize; const float vIncrement = 1.f/(float)m_TexSize; const float uHalfIncrement = uIncrement*.5f; const float vHalfIncrement = vIncrement*.5f; ParameterizationVertex * p0; ParameterizationVertex * p1; ParameterizationVertex * p2; //0 is smallest y value //1 is smallest x value that's not 0 TriangleTextureMapping toAdd; Vec3 barycentric; float u; float uMax; for( int i = 0; i < (int)m_Faces->size(); i++ ) { TriangleFace &tri = (*m_Faces)[ i ]; bool DangerTriangle = false; //get verts p0 = &(*m_CollapsedMesh)[ tri.index[ 0 ] ]; p1 = &(*m_CollapsedMesh)[ tri.index[ 1 ] ]; p2 = &(*m_CollapsedMesh)[ tri.index[ 2 ] ]; NormalizeUV( p1->generatedU ); NormalizeUV( p1->generatedV ); NormalizeUV( p2->generatedU ); NormalizeUV( p2->generatedV ); NormalizeUV( p0->generatedU ); NormalizeUV( p0->generatedV ); if( p0->generatedV > p1->generatedV ) { SwapPointers( &p0, &p1 ); } if( p0->generatedV > p2->generatedV ) { SwapPointers( &p0, &p2 ); } if( p1->generatedU > p2->generatedU ) { SwapPointers( &p1, &p2 ); } //find slopes float slope1, slope2, slope3, slope4; bool undefinedSlope[4]; undefinedSlope[0] = false; undefinedSlope[1] = false; undefinedSlope[2] = false; undefinedSlope[3] = false; if( fabs( p0->generatedV - p1->generatedV ) <= EPSILON_ZERO ) { undefinedSlope[0] = true; } if( fabs( p0->generatedV - p2->generatedV ) <= EPSILON_ZERO ) { undefinedSlope[1] = true; } if( fabs( p1->generatedV - p2->generatedV ) <= EPSILON_ZERO ) { undefinedSlope[2] = true; } if( fabs( p2->generatedV - p1->generatedV ) <= EPSILON_ZERO ) { undefinedSlope[3] = true; } slope1 = ( p0->generatedU - p1->generatedU )/(p0->generatedV - p1->generatedV ); slope2 = ( p0->generatedU - p2->generatedU )/(p0->generatedV - p2->generatedV ); slope3 = ( p1->generatedU - p2->generatedU )/(p1->generatedV - p2->generatedV ); slope4 = ( p2->generatedU - p1->generatedU )/(p2->generatedV - p1->generatedV ); float maxV = ( p1->generatedV > p2->generatedV ) ? p1->generatedV : p2->generatedV; float maxU = ( p0->generatedU > p2->generatedU ) ? p0->generatedU : p2->generatedU; maxU += uIncrement; maxV += vHalfIncrement; for( float v = p0->generatedV - vHalfIncrement; v <= maxV ; v += vIncrement ) { if( p1->generatedV >= v && p2->generatedV >= v ) { //find endpoints of scanline u = undefinedSlope[0] ? p1->generatedU : p1->generatedU + slope1*( v - p1->generatedV ) - uHalfIncrement; uMax = undefinedSlope[1] ? p2->generatedU : p2->generatedU + slope2*( v - p2->generatedV ) + uHalfIncrement; } else if( p2->generatedV <= v ) { //find endpoints of scanline u = undefinedSlope[0] ? p1->generatedU : p1->generatedU + slope1*( v - p1->generatedV )- uHalfIncrement; uMax = undefinedSlope[3] ? p2->generatedU : p1->generatedU + slope4*( v - p1->generatedV ) + uHalfIncrement; } else // p1->v is smaller than v, we're need a new edge { //find endpoints of scanline u = undefinedSlope[2] ? p1->generatedU : p2->generatedU + slope3*( v - p2->generatedV ) - uHalfIncrement; uMax = undefinedSlope[1] ? p2->generatedU : p2->generatedU + slope2*( v - p2->generatedV ) + uHalfIncrement; } if( u > uMax ){ float temp = u; u = uMax; uMax = temp; } uMax = min( uMax, maxU ); float umin = min( p1->generatedU, p0->generatedU - uIncrement); u = max( u, umin); for( ; u <= uMax; u+= uIncrement ) { //we have u and v, get barycentric: //check if slope will be undefined float qX, qY; float slopeBC, b2, b1, slope; float slopeDenom = u - p0->generatedU; float slopeDenom2 = p1->generatedU - p2->generatedU; if( slopeDenom == 0 && slopeDenom2 != 0) { //vertical line, we know x coordinate slopeBC = ( p1->generatedV - p2->generatedV )/( p1->generatedU - p2->generatedU ); b2 = p1->generatedV - slopeBC*p1->generatedU; //solve for y with known x coordinate qX = p0->generatedU; qY = slopeBC*qX + b2; }else if( slopeDenom2 != 0 && slopeDenom != 0 ) { slope = ( v - p0->generatedV )/slopeDenom; //find other slope, will never be undefined slopeBC = ( p1->generatedV - p2->generatedV )/( p1->generatedU - p2->generatedU ); //now solve for intersect b1 = v - slope*u; b2 = p1->generatedV - slopeBC*p1->generatedU; qX = ( b1 - b2 )/(slopeBC - slope); qY = slope*qX + b1; //now find length for bary }else if( slopeDenom2 == 0 && slopeDenom != 0 ) { slope = ( v - p0->generatedV )/slopeDenom; //now solve for intersect b1 = v - slope*u; qX = p2->generatedU; qY = slope*qX + b1; //now find length for bary }else //both equal 0 { //this should never happen! OutputDebugString("Slopes of two triangle sides are both zero!!!\n"); qX = p2->generatedU; qY = p2->generatedV; } barycentric.z = Vec2Length( p1->generatedU - qX, p1->generatedV - qY ); barycentric.y = Vec2Length( p2->generatedU - qX, p2->generatedV - qY ); //now find t to balance these out at q on p float ratio = Vec2Length( qX - u, qY - v ) /Vec2Length( u - p0->generatedU, v - p0->generatedV); barycentric.x = ( barycentric.y + barycentric.z )*ratio; float normalize = barycentric.x + barycentric.y + barycentric.z; if( normalize != 0 ) { barycentric.x /= normalize; barycentric.y /= normalize; barycentric.z /= normalize; toAdd.localSpaceCoord = p0->originalPosition*barycentric.x + p1->originalPosition*barycentric.y + p2->originalPosition*barycentric.z; if( toAdd.localSpaceCoord.x != toAdd.localSpaceCoord.x ) { DangerTriangle = true; //OutputDebugString( "DANGER WILL ROBINSON\n"); } toAdd.localNormal = p0->normal*barycentric.x + p1->normal*barycentric.y + p2->normal*barycentric.z; toAdd.u = (int)( u*(float)m_TexSize ); toAdd.v = (int)( v*(float)m_TexSize ); if( toAdd.localSpaceCoord.x == toAdd.localSpaceCoord.x && toAdd.u >= 0 && toAdd.u < m_TexSize && toAdd.v >= 0 && toAdd.v < m_TexSize ) { tri.m_Pixels.push_back( toAdd ); } } } static int numcont = 0; numcont++; if( DangerTriangle && numcont < 200 ) { ADDLINEPARAMS LineParam; static CHashString h(_T("none")); LineParam.name = &h; LineParam.blue = 0; LineParam.green = 0; LineParam.red = 255; LineParam.start = p0->originalPosition; LineParam.end = p1->originalPosition; //static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); //EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); LineParam.start = p0->originalPosition; LineParam.end = p2->originalPosition; //EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); LineParam.start = p2->originalPosition; LineParam.end = p1->originalPosition; //EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } } //test code #if ENABLE_DEBUG_DEGENERATES Vec3 edge1 = Vec3( p0->generatedU, p0->generatedV, 0 ) - Vec3( p1->generatedU, p1->generatedV, 0 ); Vec3 edge2 = Vec3( p0->generatedU, p0->generatedV, 0 ) - Vec3( p2->generatedU, p2->generatedV, 0 ); float lengthA = edge1.Length(); float lengthB = (Vec3( p1->generatedU, p1->generatedV, 0 ) - Vec3( p2->generatedU, p2->generatedV, 0 )).Length(); float lengthC = edge2.Length(); float halfPerimeter = (lengthA + lengthB + lengthC)*.500f; float area = halfPerimeter*( halfPerimeter - lengthA )*(halfPerimeter - lengthB )*(halfPerimeter - lengthC); area = sqrt( area ); float numPixels = (float)tri.m_Pixels.size(); edge1.Normalize(); edge2.Normalize(); float flatTriangle = edge2.Dot( edge1 ); //if( fabs( flatTriangle ) < .7f) { area *= (float)(m_TexSize*m_TexSize); float areaRatio = numPixels/area; if( areaRatio < .8f ) //half the uv pixels aren't generate?!#! { blah ref; ref.area = area; ref.pixels = (int)numPixels; ref.index = i; s_DegenerateList.insert( pair< float, blah >( numPixels, ref ) ); } } #endif if( tri.m_Pixels.size() < 2) { //something wrong here //OutputDebugString("Degenerate Triangle\n"); //OutputVector( p0->originalPosition, "p0" ); //OutputVector( p1->originalPosition, "p1" ); //OutputVector( p2->originalPosition, "p2" ); //int a = 0; } } #if ENABLE_DEBUG_DEGENERATES static char buf[1024]; for( map< float, blah >::iterator iter = s_DegenerateList.begin(); iter != s_DegenerateList.end(); ++iter ) { blah &ref = iter->second; TriangleFace &tri = (*m_Faces)[ ref.index ]; //get verts p0 = &(*m_CollapsedMesh)[ tri.index[ 0 ] ]; p1 = &(*m_CollapsedMesh)[ tri.index[ 1 ] ]; p2 = &(*m_CollapsedMesh)[ tri.index[ 2 ] ]; //sprintf( buf, "Degenerate Triangle with area: %f, pixels: %d, index: %d \n", ref.area, ref.pixels, ref.index ); //OutputDebugString( buf ); //OutputVector( p0->originalPosition, "p0" ); //OutputVector( p1->originalPosition, "p1" ); //OutputVector( p2->originalPosition, "p2" ); ADDLINEPARAMS LineParam; static CHashString h(_T("none")); LineParam.name = &h; LineParam.blue = 0; LineParam.green = 0; LineParam.red = 255; LineParam.start = p0->originalPosition; LineParam.end = p1->originalPosition; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); LineParam.start = p0->originalPosition; LineParam.end = p2->originalPosition; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); LineParam.start = p2->originalPosition; LineParam.end = p1->originalPosition; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } #endif }