static void bezier(BezierShape &shape,float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { //DebugPrint(_T("Bezier creating %.2f %.2f-%.2f %.2f-%.2f %.2f-%.2f %.2f\n"),x0,y0,x1,y1,x2,y2,x3,y3); if(!curSpline) curSpline = shape.NewSpline(); int knots = curSpline->KnotCount(); if(knots == 0) { curSpline->AddKnot(SplineKnot(KTYPE_BEZIER, LTYPE_CURVE, Point3(x0,y0,0.0f), Point3(x0,y0,0.0f), Point3(x1,y1,0.0f))); curSpline->AddKnot(SplineKnot(KTYPE_BEZIER, LTYPE_CURVE, Point3(x3,y3,0.0f), Point3(x2,y2,0.0f), Point3(x3,y3,0.0f))); } else { // First point of this curve must be the same as the last point on the output curve assert(curSpline->GetKnotPoint(knots-1) == Point3(x0,y0,0.0f)); curSpline->SetOutVec(knots-1, Point3(x1,y1,0.0f)); if(Point3(x3,y3,0.0f) == curSpline->GetKnotPoint(0)) { curSpline->SetInVec(0, Point3(x2,y2,0.0f)); curSpline->SetClosed(); //DebugPrint(_T("Bezier autoclosed\n")); curSpline = NULL; } else curSpline->AddKnot(SplineKnot(KTYPE_BEZIER, LTYPE_CURVE, Point3(x3,y3,0.0f), Point3(x2,y2,0.0f), Point3(x3,y3,0.0f))); } }
void EllipseObject::BuildShape(TimeValue t, BezierShape& ashape) { // Start the validity interval at forever and whittle it down. ivalid = FOREVER; float length; float width; pblock->GetValue(PB_LENGTH, t, length, ivalid); pblock->GetValue(PB_WIDTH, t, width, ivalid); LimitValue( length, MIN_LENGTH, MAX_LENGTH ); LimitValue( width, MIN_WIDTH, MAX_WIDTH ); // Delete the existing shape and create a new spline in it ashape.NewShape(); // Get parameters from SimpleSpline and place them in the BezierShape int steps; BOOL optimize,adaptive; ipblock->GetValue(IPB_STEPS, t, steps, ivalid); ipblock->GetValue(IPB_OPTIMIZE, t, optimize, ivalid); ipblock->GetValue(IPB_ADAPTIVE, t, adaptive, ivalid); ashape.steps = adaptive ? -1 : steps; ashape.optimize = optimize; float radius, xmult, ymult; if(length < width) { radius = width; xmult = 1.0f; ymult = length / width; } else if(width < length) { radius = length; xmult = width / length; ymult = 1.0f; } else { radius = length; xmult = ymult = 1.0f; } MakeCircle(ashape, radius / 2.0f, xmult, ymult); ashape.UpdateSels(); // Make sure it readies the selection set info ashape.InvalidateGeomCache(); }
void DonutObject::BuildShape(TimeValue t, BezierShape& ashape) { // Start the validity interval at forever and whittle it down. ivalid = FOREVER; float radius1; float radius2; pblock->GetValue(PB_RADIUS1, t, radius1, ivalid); if(mPipe) { float thickness; pblock->GetValue(PB_THICKNESS, t, thickness, ivalid); radius2 = radius1-thickness; } else { pblock->GetValue(PB_RADIUS2, t, radius2, ivalid); } LimitValue( radius1, MIN_RADIUS, MAX_RADIUS ); LimitValue( radius2, MIN_RADIUS, MAX_RADIUS ); ashape.NewShape(); // Get parameters from SimpleSpline and place them in the BezierShape int steps; BOOL optimize,adaptive; ipblock->GetValue(IPB_STEPS, t, steps, ivalid); ipblock->GetValue(IPB_OPTIMIZE, t, optimize, ivalid); ipblock->GetValue(IPB_ADAPTIVE, t, adaptive, ivalid); ashape.steps = adaptive ? -1 : steps; ashape.optimize = optimize; MakeCircle(ashape,radius1); MakeCircle(ashape,radius2); ashape.UpdateSels(); // Make sure it readies the selection set info ashape.InvalidateGeomCache(); }
static void MakeCircle(BezierShape& ashape, float radius) { float vector = CIRCLE_VECTOR_LENGTH * radius; // Delete all points in the existing spline Spline3D *spline = ashape.NewSpline(); // Now add all the necessary points for(int ix=0; ix<4; ++ix) { float angle = 6.2831853f * (float)ix / 4.0f; float sinfac = (float)sin(angle), cosfac = (float)cos(angle); Point3 p(cosfac * radius, sinfac * radius, 0.0f); Point3 rotvec = Point3(sinfac * vector, -cosfac * vector, 0.0f); spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p,p + rotvec,p - rotvec)); } spline->SetClosed(); spline->ComputeBezPoints(); }
BOOL TrueTypeImport::BuildCharacter(UINT index, float height, BezierShape &shape, float &width, int fontShapeVersion) { assert(hFont); if(!hFont) return 0; // Set up for the font and release it when this function returns FontReady fontRdy(hFont); // allocate space for the bitmap/outline GLYPHMETRICS gm; // init it to prevent UMR in GetGlyphOutline gm.gmBlackBoxX = gm.gmBlackBoxY = gm.gmptGlyphOrigin.x = gm.gmptGlyphOrigin.y = gm.gmCellIncX = gm.gmCellIncY = 0; // Give it an identity matrix MAT2 mat; IdentityMat(&mat); // get unicode outline DWORD size= GetGlyphOutlineW(fontRdy.hdc, index, GGO_GLYPH_INDEX|GGO_NATIVE, &gm, 0, NULL, &mat); if(size != GDI_ERROR && size > 0) { GenericAlloc mem(size); if(!mem.ptr) goto failure; // get unicode outline if ((GetGlyphOutlineW(fontRdy.hdc, index, GGO_GLYPH_INDEX|GGO_NATIVE, &gm, size, mem.ptr, &mat)) != size) goto failure; curSpline = NULL; // reset the current spline pointer if(!CreateCharacterShape((TTPOLYGONHEADER *)mem.ptr, size, shape, fontShapeVersion)) goto failure; // Make sure the height matches the request float scaleFactor = height / 1000.0f; Matrix3 tm = ScaleMatrix(Point3(scaleFactor, scaleFactor, 0.0f)); shape.Transform(tm); width = float(gm.gmCellIncX) * scaleFactor; return TRUE; } // Character wasn't found! failure: width = 0.0f; return FALSE; }
void RectangleObject::BuildShape(TimeValue t, BezierShape& ashape) { // Start the validity interval at forever and whittle it down. ivalid = FOREVER; float length,fillet; float width; pblock->GetValue(PB_LENGTH, t, length, ivalid); pblock->GetValue(PB_WIDTH, t, width, ivalid); pblock->GetValue(PB_FILLET, t, fillet, ivalid); LimitValue( length, MIN_LENGTH, MAX_LENGTH ); LimitValue( width, MIN_WIDTH, MAX_WIDTH ); LimitValue( fillet, MIN_WIDTH, MAX_WIDTH ); // Delete the existing shape and create a new spline in it ashape.NewShape(); // Get parameters from SimpleSpline and place them in the BezierShape int steps; BOOL optimize,adaptive; ipblock->GetValue(IPB_STEPS, t, steps, ivalid); ipblock->GetValue(IPB_OPTIMIZE, t, optimize, ivalid); ipblock->GetValue(IPB_ADAPTIVE, t, adaptive, ivalid); ashape.steps = adaptive ? -1 : steps; ashape.optimize = optimize; Spline3D *spline = ashape.NewSpline(); // Now add all the necessary points // We'll add 'em as auto corners initially, have the spline package compute some vectors (because // I'm basically lazy and it does a great job, besides) then turn 'em into bezier corners! float l2 = length / 2.0f; float w2 = width / 2.0f; Point3 p = Point3(w2, l2, 0.0f); int pts=4; if (fillet>0) { pts=8; float cf=fillet*CIRCLE_VECTOR_LENGTH; Point3 wvec=Point3(fillet,0.0f,0.0f),lvec=Point3(0.0f,fillet,0.0f); Point3 cwvec=Point3(cf,0.0f,0.0f),clvec=Point3(0.0f,cf,0.0f); Point3 p3=p-lvec,p2; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p3,p3-clvec,p3+clvec)); p=p-wvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p,p+cwvec,p-cwvec)); p=Point3(-w2,l2,0.0f);p2=p+wvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p2,p2+cwvec,p2-cwvec)); p=p-lvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p,p+clvec,p-clvec)); p=Point3(-w2,-l2,0.0f);p3=p+lvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p3,p3+clvec,p3-clvec)); p=p+wvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p,p-cwvec,p+cwvec)); p = Point3(w2, -l2, 0.0f);p3=p-wvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p3,p3-cwvec,p3+cwvec)); p=p+lvec; spline->AddKnot(SplineKnot(KTYPE_BEZIER,LTYPE_CURVE,p,p-clvec,p+clvec)); spline->SetClosed(); spline->ComputeBezPoints(); } else {spline->AddKnot(SplineKnot(KTYPE_CORNER,LTYPE_CURVE,p,p,p)); p = Point3(-w2, l2, 0.0f); spline->AddKnot(SplineKnot(KTYPE_CORNER,LTYPE_CURVE,p,p,p)); p = Point3(-w2, -l2, 0.0f); spline->AddKnot(SplineKnot(KTYPE_CORNER,LTYPE_CURVE,p,p,p)); p = Point3(w2, -l2, 0.0f); spline->AddKnot(SplineKnot(KTYPE_CORNER,LTYPE_CURVE,p,p,p)); spline->SetClosed(); spline->ComputeBezPoints(); for(int i = 0; i < 4; ++i) spline->SetKnotType(i, KTYPE_BEZIER_CORNER); } spline->SetClosed(); spline->ComputeBezPoints(); for(int i = 0; i < pts; ++i) spline->SetKnotType(i, KTYPE_BEZIER_CORNER); ashape.UpdateSels(); // Make sure it readies the selection set info ashape.InvalidateGeomCache(); }
bool AlembicCurves::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); //TimeValue ticks = GET_MAX_INTERFACE()->GetTime(); TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; if(mNumSamples == 0){ bForever = CheckIfObjIsValidForever(obj, ticks); } else{ bool bNewForever = CheckIfObjIsValidForever(obj, ticks); if(bForever && bNewForever != bForever){ ESS_LOG_INFO( "bForever has changed" ); } } SaveMetaData(mMaxNode, this); // check if the spline is animated if(mNumSamples > 0) { if(bForever) { return true; } } AbcG::OCurvesSchema::Sample curvesSample; std::vector<AbcA::int32_t> nbVertices; std::vector<Point3> vertices; std::vector<float> knotVector; std::vector<Abc::uint16_t> orders; if(obj->ClassID() == EDITABLE_SURF_CLASS_ID){ NURBSSet nurbsSet; BOOL success = GetNURBSSet(obj, ticks, nurbsSet, TRUE); AbcG::CurvePeriodicity cPeriod = AbcG::kNonPeriodic; AbcG::CurveType cType = AbcG::kCubic; AbcG::BasisType cBasis = AbcG::kNoBasis; int n = nurbsSet.GetNumObjects(); for(int i=0; i<n; i++){ NURBSObject* pObject = nurbsSet.GetNURBSObject((int)i); //NURBSType type = pObject->GetType(); if(!pObject){ continue; } if( pObject->GetKind() == kNURBSCurve ){ NURBSCurve* pNurbsCurve = (NURBSCurve*)pObject; int degree; int numCVs; NURBSCVTab cvs; int numKnots; NURBSKnotTab knots; pNurbsCurve->GetNURBSData(ticks, degree, numCVs, cvs, numKnots, knots); orders.push_back(degree+1); const int cvsCount = cvs.Count(); const int knotCount = knots.Count(); for(int j=0; j<cvs.Count(); j++){ NURBSControlVertex cv = cvs[j]; double x, y, z; cv.GetPosition(ticks, x, y, z); vertices.push_back( Point3((float)x, (float)y, (float)z) ); } nbVertices.push_back(cvsCount); //skip the first and last entry because Maya and XSI use this format for(int j=1; j<knots.Count()-1; j++){ knotVector.push_back((float)knots[j]); } if(i == 0){ if(pNurbsCurve->IsClosed()){ cPeriod = AbcG::kPeriodic; } } else{ if(pNurbsCurve->IsClosed()){ if(cPeriod != AbcG::kPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } else{ if(cPeriod != AbcG::kNonPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } } } } curvesSample.setType(cType); curvesSample.setWrap(cPeriod); curvesSample.setBasis(cBasis); } else { BezierShape beziershape; PolyShape polyShape; bool bBezier = false; // Get a pointer to the spline shpae ShapeObject *pShapeObject = NULL; if (obj->IsShapeObject()) { pShapeObject = reinterpret_cast<ShapeObject *>(obj); } else { return false; } // Determine if we are a bezier shape if (pShapeObject->CanMakeBezier()) { pShapeObject->MakeBezier(ticks, beziershape); bBezier = true; } else { pShapeObject->MakePolyShape(ticks, polyShape); bBezier = false; } // Get the control points //std::vector<Point3> inTangents; //std::vector<Point3> outTangents; if (bBezier) { int oldVerticesCount = (int)vertices.size(); for (int i = 0; i < beziershape.SplineCount(); i += 1) { Spline3D *pSpline = beziershape.GetSpline(i); int knots = pSpline->KnotCount(); for(int ix = 0; ix < knots; ++ix) { Point3 in = pSpline->GetInVec(ix); Point3 p = pSpline->GetKnotPoint(ix); Point3 out = pSpline->GetOutVec(ix); vertices.push_back( p ); //inTangents.push_back( in ); //outTangents.push_back( out ); } int nNumVerticesAdded = (int)vertices.size() - oldVerticesCount; nbVertices.push_back( nNumVerticesAdded ); oldVerticesCount = (int)vertices.size(); } } else { for (int i = 0; i < polyShape.numLines; i += 1) { PolyLine &refLine = polyShape.lines[i]; nbVertices.push_back(refLine.numPts); for (int j = 0; j < refLine.numPts; j += 1) { Point3 p = refLine.pts[j].p; vertices.push_back(p); } } } // set the type + wrapping curvesSample.setType(bBezier ? AbcG::kCubic : AbcG::kLinear); curvesSample.setWrap(pShapeObject->CurveClosed(ticks, 0) ? AbcG::kPeriodic : AbcG::kNonPeriodic); curvesSample.setBasis(AbcG::kNoBasis); } if(nbVertices.size() == 0 || vertices.size() == 0){ ESS_LOG_WARNING("No curve data to export."); return false; } const int vertCount = (int)vertices.size(); // prepare the bounding box Abc::Box3d bbox; // allocate the points and normals std::vector<Abc::V3f> posVec(vertCount); Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks); for(int i=0;i<vertCount;i++) { posVec[i] = ConvertMaxPointToAlembicPoint(vertices[i] ); bbox.extendBy(posVec[i]); // Set the archive bounding box if (mJob) { Point3 worldMaxPoint = wm * vertices[i]; Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint); mJob->GetArchiveBBox().extendBy(alembicWorldPoint); } } if(knotVector.size() > 0 && orders.size() > 0){ if(!mKnotVectorProperty.valid()){ mKnotVectorProperty = Abc::OFloatArrayProperty(mCurvesSchema.getArbGeomParams(), ".knot_vector", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mKnotVectorProperty.set(Abc::FloatArraySample(knotVector)); if(!mOrdersProperty.valid()){ mOrdersProperty = Abc::OUInt16ArrayProperty(mCurvesSchema.getArbGeomParams(), ".orders", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mOrdersProperty.set(Abc::UInt16ArraySample(orders)); } // store the bbox curvesSample.setSelfBounds(bbox); mCurvesSchema.getChildBoundsProperty().set(bbox); Abc::Int32ArraySample nbVerticesSample(&nbVertices.front(),nbVertices.size()); curvesSample.setCurvesNumVertices(nbVerticesSample); // allocate for the points and normals Abc::P3fArraySample posSample(&posVec.front(),posVec.size()); curvesSample.setPositions(posSample); mCurvesSchema.set(curvesSample); mNumSamples++; return true; }
int CrossSectionMouseProc::proc( HWND hwnd, int msg, int point, int flags, IPoint2 m ) { ViewExp *vpt = NULL; HitRecord *rec = NULL; int res = TRUE; switch ( msg ) { case MOUSE_ABORT: if (mCreating) { if (mCrossingDrawn) DrawCrossing(hwnd); // erase the previous line mCreating = false; es->EndCrossSection(mSelectedSplines.Count() > 1 ? TRUE : FALSE); } res = FALSE; break; case MOUSE_PROPCLICK: ip->SetStdCommandMode(CID_OBJMOVE); res = FALSE; break; case MOUSE_POINT: vpt = ip->GetViewport(hwnd); if((rec = HitTest(vpt,&m,HITTYPE_POINT,0)) != NULL) { ShapeHitData *hit = ((ShapeHitData *)rec->hitData); int poly = hit->poly; mObjToWorldTM = rec->nodeRef->GetObjectTM(ip->GetTime()); if (!mCreating) { if (!es->StartCrossSection(&mShapeData)) return CREATE_ABORT; mCreating = true; mSelectedSplines.ZeroCount(); BezierShape *shape = mShapeData->TempData(es)->GetShape(ip->GetTime()); mPolys = (shape == NULL) ? 0 : shape->SplineCount(); } mSelectedSplines.Append(1, &poly, 1); es->DoCrossSection(mShapeData, mSelectedSplines); mMouse = m; mCrossingDrawn = false; } ip->ReleaseViewport(vpt); if (!mCreating) res = FALSE; break; case MOUSE_MOVE: if (mCreating) { if (mCrossingDrawn) DrawCrossing(hwnd); // erase the previous line mMouse = m; DrawCrossing(hwnd); mCrossingDrawn = true; } // continue to the next case to set cursor. case MOUSE_FREEMOVE: vpt = ip->GetViewport(hwnd); if ( HitTest(vpt,&m,HITTYPE_POINT,HIT_ABORTONHIT) ) SetCursor(GetTransformCursor()); else SetCursor(LoadCursor(NULL,IDC_ARROW)); ip->ReleaseViewport(vpt); break; } return res; }
void ExtrudeMod::BuildPatchFromShape(TimeValue t,ModContext &mc, ObjectState * os, PatchMesh &pmesh) { ShapeObject *shape = (ShapeObject *)os->obj; float amount; int levels,capStart,capEnd,capType; pblock->GetValue(PB_AMOUNT,t,amount,FOREVER); pblock->GetValue(PB_SEGS,t,levels,FOREVER); if (levels<1) levels = 1; pblock->GetValue(PB_CAPSTART,t,capStart,FOREVER); pblock->GetValue(PB_CAPEND,t,capEnd,FOREVER); pblock->GetValue(PB_CAPTYPE,t,capType,FOREVER); BOOL texturing; pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER); BOOL genMatIDs; pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER); BOOL useShapeIDs; pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER); BOOL smooth; pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER); LimitValue(amount, -1000000.0f, 1000000.0f); // Get the basic dimension stuff float zSize = (float)fabs(amount); float baseZ = 0.0f; if(amount < 0.0f) baseZ = amount; // If the shape can convert itself to a BezierShape, have it do so! BezierShape bShape; if(shape->CanMakeBezier()) shape->MakeBezier(t, bShape); else { PolyShape pShape; shape->MakePolyShape(t, pShape); bShape = pShape; // UGH -- Convert it from a PolyShape -- not good! } //DebugPrint(_T("Extrude organizing shape\n")); ShapeHierarchy hier; bShape.OrganizeCurves(t, &hier); // Need to flip the reversed polys... bShape.Reverse(hier.reverse); // ...and tell the hierarchy they're no longer reversed! hier.reverse.ClearAll(); // Our shapes are now organized for patch-making -- Let's do the sides! int polys = bShape.splineCount; int poly, knot; int levelVerts = 0, levelVecs = 0, levelPatches = 0, nverts = 0, nvecs = 0, npatches = 0; int TVlevels = levels + 1, levelTVerts = 0, ntverts = 0, ntpatches = 0; BOOL anyClosed = FALSE; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; if(spline->Closed()) anyClosed = TRUE; levelVerts += spline->KnotCount(); levelTVerts += (spline->Segments() + 1); levelVecs += (spline->Segments() * 2); levelPatches += spline->Segments(); } nverts = levelVerts * (levels + 1); npatches = levelPatches * levels; nvecs = (levelVecs * (levels + 1)) + levels * levelVerts * 2 + npatches * 4; if(texturing) { ntverts = levelTVerts * TVlevels; ntpatches = npatches; } pmesh.setNumVerts(nverts); pmesh.setNumVecs(nvecs); pmesh.setNumPatches(npatches); pmesh.setNumTVerts(ntverts); pmesh.setNumTVPatches(ntpatches); // Create the vertices! int vert = 0; int level; Point3 offset1, offset2; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int knots = spline->KnotCount(); for(level = 0; level <= levels; ++level) { Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); if(level == 0) offset1 = offset; else if(level == levels) offset2 = offset; for(knot = 0; knot < knots; ++knot) { Point3 p = spline->GetKnotPoint(knot); pmesh.setVert(vert++, p + offset); } } } assert(vert == nverts); BOOL usePhysUVs = GetUsePhysicalScaleUVs(); // Maybe create the texture vertices if(texturing) { int tvert = 0; int level; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; // Make it a polyline PolyLine pline; spline->MakePolyLine(pline, 10); int knots = spline->KnotCount(); for(level = 0; level < TVlevels; ++level) { float tV = (float)level / (float)(TVlevels - 1); float vScale = usePhysUVs ? amount : 1.0f; int lverts = pline.numPts; int tp = 0; int texPts = spline->Segments() + 1; float cumLen = 0.0f; float totLen = pline.CurveLength(); float uScale = usePhysUVs ? totLen : 1.0f; Point3 prevPt = pline.pts[0].p; int plix = 0; while(tp < texPts) { Point3 &pt = pline[plix].p; cumLen += Length(pt - prevPt); prevPt = pt; if(pline[plix].flags & POLYPT_KNOT) { float tU; if(tp == (texPts - 1)) tU = 1.0f; else tU = cumLen / totLen; pmesh.setTVert(tvert++, UVVert(uScale*tU, vScale*tV, 0.0f)); tp++; } plix = (plix + 1) % pline.numPts; } } } assert(tvert == ntverts); } // Create the vectors! int seg; int vec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int segs = spline->Segments(); int knots = spline->KnotCount(); // First, the vectors on each level for(level = 0; level <= levels; ++level) { Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); for(seg = 0; seg < segs; ++seg) { int seg2 = (seg + 1) % knots; if(spline->GetLineType(seg) == LTYPE_CURVE) { Point3 p = spline->GetOutVec(seg); pmesh.setVec(vec++, p + offset); p = spline->GetInVec(seg2); pmesh.setVec(vec++, p + offset); } else { Point3 p = spline->InterpBezier3D(seg, 0.333333f); pmesh.setVec(vec++, p + offset); p = spline->InterpBezier3D(seg, 0.666666f); pmesh.setVec(vec++, p + offset); } } } // Now, the vectors between the levels int baseVec = vec; for(level = 0; level < levels; ++level) { Point3 offsetA = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); Point3 offsetB = Point3(0.0f, 0.0f, baseZ + (float)(level + 1) / (float)levels * zSize); Point3 offset1 = offsetA + (offsetB - offsetA) * 0.333333333f; Point3 offset2 = offsetA + (offsetB - offsetA) * 0.666666666f; for(knot = 0; knot < knots; ++knot) { Point3 p = spline->GetKnotPoint(knot); pmesh.setVec(vec++, p + offset1); pmesh.setVec(vec++, p + offset2); } } } // Create the patches! int np = 0; int baseVert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int knots = spline->KnotCount(); int segs = spline->Segments(); int baseVec1 = baseVec; // Base vector index for this level int baseVec2 = baseVec + segs * 2 * (levels + 1); // Base vector index for between levels for(level = 0; level < levels; ++level) { int sm = 0; BOOL firstSmooth = (spline->GetLineType(0) == LTYPE_CURVE && spline->GetLineType(segs-1) == LTYPE_CURVE && (spline->GetKnotType(0) == KTYPE_AUTO || spline->GetKnotType(0) == KTYPE_BEZIER)) ? TRUE : FALSE; for(seg = 0; seg < segs; ++seg, vec += 4) { int prevseg = (seg + segs - 1) % segs; int seg2 = (seg + 1) % knots; int a,b,c,d,ab,ba,bc,cb,cd,dc,da,ad; MtlID mtl = useShapeIDs ? spline->GetMatID(seg) : 2; a = baseVert + seg; b = baseVert + seg2; c = b + knots; d = a + knots; ab = baseVec1 + seg * 2; ba = ab + 1; bc = baseVec2 + seg2 * 2; cb = bc + 1; cd = ba + (segs * 2); dc = ab + (segs * 2); da = baseVec2 + seg * 2 + 1; ad = da - 1; //DebugPrint(_T("Making patch %d: %d (%d %d) %d (%d %d) %d (%d %d) %d (%d %d)\n"),np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad); // If the vertex is not smooth, go to the next group! if(seg > 0 && !(spline->GetLineType(prevseg) == LTYPE_CURVE && spline->GetLineType(seg) == LTYPE_CURVE && (spline->GetKnotType(seg) == KTYPE_AUTO || spline->GetKnotType(seg) == KTYPE_BEZIER))) { sm++; if(sm > 2) sm = 1; } DWORD smoothGroup = 1 << sm; if(seg == segs - 1 && firstSmooth) { smoothGroup |= 1; } pmesh.MakeQuadPatch(np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad, vec, vec+1, vec+2, vec+3, smooth ? smoothGroup : 0); pmesh.setPatchMtlIndex(np++, genMatIDs ? mtl : 0); } baseVert += knots; baseVec1 += (segs * 2); baseVec2 += (knots * 2); } baseVert += knots; baseVec += (segs * 2 * (levels + 1) + knots * 2 * levels); } assert(vec == nvecs); assert(np == npatches); // Maybe create the texture patches! if(texturing) { int ntp = 0; int baseTVert = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int pknots = spline->Segments() + 1; int pverts = pknots * TVlevels; int segs = spline->Segments(); for(level = 0; level < levels; ++level) { for(seg = 0; seg < segs; ++seg) { int prevseg = (seg + segs - 1) % segs; int seg2 = seg + 1; int a,b,c,d; a = baseTVert + seg; b = baseTVert + seg2; c = b + pknots; d = a + pknots; TVPatch &tp = pmesh.getTVPatch(ntp++); tp.setTVerts(a, b, c, d); } baseTVert += pknots; } baseTVert += pknots; } assert(ntp == ntpatches); } // If capping, do it! if(anyClosed && (capStart || capEnd)) { PatchCapInfo capInfo; bShape.MakeCap(t, capInfo); // Build information for capping PatchCapper capper(bShape); if(capStart) { vert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; PatchCapPoly &capline = capper[poly]; int lverts = spline->KnotCount(); for(int v = 0; v < lverts; ++v) capline.SetVert(v, vert++); // Gives this vert's location in the mesh! vert += lverts * levels; vec = baseVec; int lvecs = spline->Segments() * 2; for(int v = 0; v < lvecs; ++v) capline.SetVec(v, vec++); // Gives this vec's location in the mesh! baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2; } // Create a work matrix for capping Matrix3 mat = TransMatrix(offset1); int oldPatches = pmesh.numPatches; capper.CapPatchMesh(pmesh, capInfo, TRUE, 16, &mat, genMatIDs ? -1 : 0); // If texturing, create the texture patches and vertices if(texturing) MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs); } if(capEnd) { int baseVert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; PatchCapPoly &capline = capper[poly]; int lverts = spline->KnotCount(); int vert = baseVert + lverts * levels; for(int v = 0; v < lverts; ++v) capline.SetVert(v, vert++); // Gives this vert's location in the mesh! baseVert += lverts * (levels + 1); int lvecs = spline->Segments()*2; int vec = baseVec + lvecs * levels; for(int v = 0; v < lvecs; ++v) capline.SetVec(v, vec++); // Gives this vec's location in the mesh! baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2; } // Create a work matrix for grid capping Matrix3 mat = TransMatrix(offset2); int oldPatches = pmesh.numPatches; capper.CapPatchMesh(pmesh, capInfo, FALSE, 16, &mat, genMatIDs ? -1 : 0); // If texturing, create the texture patches and vertices if(texturing) MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs); } } //watje new mapping if(texturing) { if (ver < 4) { for (int i = 0; i < pmesh.numPatches; i++) pmesh.patches[i].flags |= PATCH_LINEARMAPPING; } } // Ready the patch representation! if( !pmesh.buildLinkages() ) { assert(0); } pmesh.computeInteriors(); }
BOOL TrueTypeImport::CreateCharacterShape(LPTTPOLYGONHEADER lpHeader, int size, BezierShape &shape, int fontShapeVersion) { LPTTPOLYGONHEADER lpStart; LPTTPOLYCURVE lpCurve; WORD i = 0; POINTFX work; //DebugPrint(_T("Start of letter\n")); lpStart = lpHeader; while ((DWORD_PTR)lpHeader < (DWORD_PTR)(((LPSTR)lpStart) + size)) { if (lpHeader->dwType == TT_POLYGON_TYPE) { // Get to first curve. lpCurve = (LPTTPOLYCURVE) (lpHeader + 1); // iFirstCurve = cTotal; //DebugPrint(_T("Poly start\n")); while ((DWORD_PTR)lpCurve < (DWORD_PTR)(((LPSTR)lpHeader) + lpHeader->cb)) { if (lpCurve->wType == TT_PRIM_LINE) { work = *(LPPOINTFX)((LPSTR)lpCurve - sizeof(POINTFX)); Point3 p0(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); for (i = 0; i < lpCurve->cpfx; i++) { work = lpCurve->apfx[i]; Point3 p1(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); bezier(shape, p0.x, p0.y, p0.x, p0.y, p1.x, p1.y, p1.x, p1.y); p0 = p1; } } else if (lpCurve->wType == TT_PRIM_QSPLINE) { //********************************************** // Format assumption: // The bytes immediately preceding a POLYCURVE // structure contain a valid POINTFX. // // If this is first curve, this points to the // pfxStart of the POLYGONHEADER. // Otherwise, this points to the last point of // the previous POLYCURVE. // // In either case, this is representative of the // previous curve's last point. //********************************************** work = *(LPPOINTFX)((LPSTR)lpCurve - sizeof(POINTFX)); Point3 p0(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); Point3 p1, p2, p3, pa, pb; for (i = 0; i < lpCurve->cpfx;) { // This point is off the curve -- Hold onto it work = lpCurve->apfx[i++]; pa = Point3(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); // Calculate the C point. if (i == (lpCurve->cpfx - 1)) { // It's the last point, and therefore on the curve. // We need to compute the bezier handles between it and p0... work = lpCurve->apfx[i++]; p3 = Point3(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); } else { // It's not the last point -- Need to compute midpoint to get // a point on the curve work = lpCurve->apfx[i]; // Don't inc i -- We'll use it next time around! Point3 pb(FloatFromFixed(work.x), FloatFromFixed(work.y), 0.0f); p3 = (pa + pb) / 2.0f; } // Also compute the appropriate handles... if(fontShapeVersion == 1) { // Release 1.x-compatible p1 = (p0 + pa) / 2.0f; p2 = (pa + p3) / 2.0f; } else{ p1 = (p0 + 2.0f * pa) / 3.0f; // Release 2 p2 = (p3 + 2.0f * pa) / 3.0f; } // Let's add it to the output bezier! bezier(shape, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); // New A point for next slice of spline. p0 = p3; } } else ; // error, error, error // Move on to next curve. lpCurve = (LPTTPOLYCURVE)&(lpCurve->apfx[i]); } //DebugPrint(_T("Poly end\n")); if(curSpline) { curSpline->SetClosed(); curSpline = NULL; } // Move on to next polygon. lpHeader = (LPTTPOLYGONHEADER)(((LPSTR)lpHeader) + lpHeader->cb); } else ; // error, error, error } //DebugPrint(_T("End of letter\n")); // Make sure any splines are closed and reset if(curSpline) { curSpline->SetClosed(); curSpline = NULL; } // Update the selection set info -- Just to be safe shape.UpdateSels(); return TRUE; }
void SWrapMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { SWrapObject *obj = (SWrapObject *)GetWSMObject(t); INode *pnode; TriObject *towrapOb=NULL;Object *pobj=NULL; if (obj) pnode=obj->custnode; if (obj && nodeRef && pnode) { Interval valid = FOREVER; if (!obj->cmValid.InInterval(t)) { pobj = pnode->EvalWorldState(t).obj; obj->cmValid=pobj->ObjectValidity(t); Matrix3 tm=pnode->GetObjectTM(t,&(obj->cmValid)); TriObject *wrapOb=IsUseable(pobj,t); if (wrapOb) { if (obj->cmesh) delete obj->cmesh; obj->cmesh=new Mesh; obj->cmesh->DeepCopy(&wrapOb->GetMesh(), PART_GEOM|SELECT_CHANNEL|PART_SUBSEL_TYPE|PART_TOPO|TM_CHANNEL); for (int ic=0;ic<obj->cmesh->getNumVerts();ic++) obj->cmesh->verts[ic]=obj->cmesh->verts[ic]*tm; GetVFLst(obj->cmesh,&obj->vnorms,&obj->fnorms); if (wrapOb!=pobj) wrapOb->DeleteThis(); } } if (!obj->cmesh) return; if ((obj->cmesh->getNumVerts()==0)||(obj->cmesh->getNumFaces()==0)) return; // Matrix3 invtm=Inverse(obj->tm); valid=obj->cmValid; Matrix3 ctm; ctm = nodeRef->GetNodeTM(t,&valid); Ray ray; Point3 v=-ctm.GetRow(2); // Matrix3 nooff=invtm;nooff.NoTrans(); ray.dir=v;//*nooff; int selverts; float kdef,standoff; obj->pblock->GetValue(PB_USESELVERTS,t,selverts,valid); obj->pblock->GetValue(PB_KIDEFAULT,t,kdef,valid); obj->pblock->GetValue(PB_STANDOFF,t,standoff,valid); BezierShape stowrapOb; int found=0; Matrix3 towtm(1); if (os->GetTM()) towtm=*(os->GetTM()); Matrix3 invtowtm=Inverse(towtm); Point3 vert; Class_ID cid=os->obj->ClassID(),es=EDITABLE_SURF_CLASS_ID,efp=FITPOINT_PLANE_CLASS_ID,ecv=EDITABLE_CVCURVE_CLASS_ID,ecfp=EDITABLE_FPCURVE_CLASS_ID; if (((cid==EDITABLE_SURF_CLASS_ID)||(cid==FITPOINT_PLANE_CLASS_ID))||((cid==EDITABLE_CVCURVE_CLASS_ID)||(cid==EDITABLE_FPCURVE_CLASS_ID))) { Object* nurbobj=os->obj; int num=nurbobj->NumPoints(); for (int i=0;i<num;i++) { vert=DoIntersect(nurbobj->GetPoint(i)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); nurbobj->SetPoint(i,(vert*invtowtm)); } } #ifndef NO_PATCHES else if (os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject* patchob=(PatchObject *)os->obj; PatchMesh *pm=&(patchob->patch); int nv=pm->getNumVerts(); BitArray sel = pm->VertSel(); for (int i=0;i<nv;i++) { if (!selverts||sel[i]) { vert=DoIntersect(pm->getVert(i).p*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); vert=vert*invtowtm; pm->setVert(i,vert); } } /* pm->buildLinkages(); pm->computeInteriors(); pm->InvalidateGeomCache();*/ } #endif // NO_PATCHES else if (towrapOb=IsUseable(os->obj,t)) { Point3 tvector; float dist; float *vssel = NULL; if (selverts) vssel = towrapOb->GetMesh().getVSelectionWeights(); for (int i=0;i<towrapOb->GetMesh().getNumVerts();i++) { if ((!selverts)||(towrapOb->GetMesh().vertSel[i]) ||(vssel&&vssel[i])) { vert = DoIntersect(towrapOb->GetMesh().verts[i]*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); vert = vert*invtowtm; if (vssel&&vssel[i]) { tvector = vert - towrapOb->GetMesh().verts[i]; dist = Length(tvector); if ((float)fabs(dist) > EPSILON) tvector = tvector/dist; else tvector = Zero; vert = towrapOb->GetMesh().verts[i] + dist*vssel[i]*tvector; } towrapOb->GetMesh().verts[i] = vert; } } if (towrapOb!=os->obj) towrapOb->DeleteThis(); } else if((os->obj->IsSubClassOf(splineShapeClassID))||(os->obj->CanConvertToType(splineShapeClassID))) { SplineShape *attSplShape = (SplineShape *)os->obj->ConvertToType(t,splineShapeClassID); if (attSplShape) { stowrapOb=attSplShape->shape; for (int poly=0; poly<stowrapOb.splineCount; ++poly) { Spline3D *spline = stowrapOb.GetSpline(poly); int verts = spline->Verts(); int knots = spline->KnotCount(); BitArray sel = stowrapOb.VertexTempSel(poly); Point3 cknot,cknot2; { for(int k=0; k<knots; ++k) { int vert = k * 3 + 1; if (!selverts||sel[vert]) { cknot=DoIntersect(spline->GetKnotPoint(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert,cknot*invtowtm); if (found) { int knotType = spline->GetKnotType(k); if(knotType & KTYPE_BEZIER) { cknot2= DoIntersect(spline->GetInVec(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert-1,(found?cknot2:cknot)*invtowtm); cknot2= DoIntersect(spline->GetOutVec(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert+1,(found?cknot2:cknot)*invtowtm); } } } } } } if (attSplShape!=os->obj) attSplShape->DeleteThis(); } } // os->obj->PointsWereChanged(); os->obj->UpdateValidity(GEOM_CHAN_NUM,valid); // NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } }