// `自适应Simpson公式(递归过程)。已知整个区间[a,b]上的三点simpson值A` double asr(double a, double b, double eps, double A) { double c = a + (b-a)/2; double L = simpson(a, c), R = simpson(c, b); if(fabs(L+R-A) <= 15*eps) return L+R+(L+R-A)/15.0; return asr(a, c, eps/2, L) + asr(c, b, eps/2, R); }
double asr(double l, double r, double eps, double area) { double m = l + (r - l) / 2; double la = simpson(l, m), ra = simpson(m, r); if(fabs(la + ra - area) <= 15 * eps) return la + ra + (la + ra - area) / 15; return asr(l, m, eps / 2, la) + asr(m, r, eps / 2, ra); }
int main() { while(scanf("%lf%lf%lf%d", &W, &D, &A, &K) == 4) { for(int i = 0; i <= K; ++i) scanf("%lf", &p[i][0]); for(int i = 0; i <= K; ++i) scanf("%lf", &p[i][1]); for(int i = 0; i <= K; ++i) scanf("%lf", &q[i][0]); for(int i = 0; i <= K; ++i) scanf("%lf", &q[i][1]); L = -D, R = 0; while(R - L >= 1e-8) { M = L + (R - L) / 2; if(asr(0, W, 1e-5, simpson(0, W)) < A) R = M; else L = M; } printf("%.5f\n", -L); } return 0; }
bool GrDrawTarget::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { if (!GrDrawTarget::onCanCopySurface(dst, src, srcRect, dstPoint)) { return false; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit); this->drawState()->setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(srcRect.fLeft - dstPoint.fX), SkIntToScalar(srcRect.fTop - dstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); this->drawState()->addColorTextureEffect(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); this->drawSimpleRect(dstRect); return true; }
int main() { while (~scanf("%d", &n) && n) { for (int i = n; i >= 0; i--) scanf("%lf", &a[i]); for (int i = 0; i < n; i++) a[i] = a[i + 1] * i; scanf("%lf%lf", &s, &e); printf("%.3lf\n", asr(s, e, eps, simpon(s, e)) / (e - s)); } return 0; }
const char* GrGLFragmentShaderBuilder::fragmentPosition() { fHasReadFragmentPosition = true; GrGLGpu* gpu = fProgramBuilder->gpu(); // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the // declaration varies in earlier GLSL specs. So it is simpler to omit it. if (fTopLeftFragPosRead) { fSetupFragPosition = true; return "gl_FragCoord"; } else if (gpu->glCaps().fragCoordConventionsSupport()) { if (!fSetupFragPosition) { if (gpu->glslGeneration() < k150_GrGLSLGeneration) { this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, "GL_ARB_fragment_coord_conventions"); } fInputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kIn_TypeModifier, "gl_FragCoord", kDefault_GrSLPrecision, GrGLShaderVar::kUpperLeft_Origin); fSetupFragPosition = true; } return "gl_FragCoord"; } else { static const char* kTempName = "tmpXYFragCoord"; static const char* kCoordName = "fragCoordYDown"; if (!fSetupFragPosition) { // temporarily change the stage index because we're inserting non-stage code. GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder); SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); const char* rtHeightName; fProgramBuilder->fUniformHandles.fRTHeightUni = fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "RTHeight", &rtHeightName); // The Adreno compiler seems to be very touchy about access to "gl_FragCoord". // Accessing glFragCoord.zw can cause a program to fail to link. Additionally, // depending on the surrounding code, accessing .xy with a uniform involved can // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand // (and only accessing .xy) seems to "fix" things. this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", kCoordName, kTempName, rtHeightName, kTempName); this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName); fSetupFragPosition = true; } SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); return kCoordName; } }
void ARMCore::thumbDataLo(uint4 opcode, uint3 ird, uint3 irm) { auto &rd = r[ird], rm = r[irm]; r[15] += 2; if(opcode == 2) { SOut r = lsl(rd, rm); bitf(true, rd = r, r); } // lsls else if(opcode == 3) { SOut r = lsr(rd, rm); bitf(true, rd = r, r); } // lsrs else if(opcode == 4) { SOut r = asr(rd, rm); bitf(true, rd = r, r); } // asrs else if(opcode == 7) { SOut r = ror(rd, rm); bitf(true, rd = r, r); } // rors else if(opcode == 9) sumf(true, rd = -rm, 0, ~rm); // negs else if(opcode == 13) bitf(true, rd = rm * rd, {rm*rd, Cf}); // muls else alu(2*opcode+1, rd, rd, {rm,Cf}); // others are same as ARM }
void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillType fill) { this->handleDirtyContext(); // TODO: make this more effecient (don't copy and copy back) GrAutoTRestore<GrStencilSettings> asr(this->drawState()->stencil()); this->setStencilPathSettings(*path, fill, this->drawState()->stencil()); if (!this->setupClipAndFlushState(kStencilPath_DrawType)) { return; } this->onGpuStencilPath(path, fill); }
const char* GrGLFragmentShaderBuilder::fragmentPosition() { fHasReadFragmentPosition = true; GrGLGpu* gpu = fProgramBuilder->gpu(); // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the // declaration varies in earlier GLSL specs. So it is simpler to omit it. if (fTopLeftFragPosRead) { fSetupFragPosition = true; return "gl_FragCoord"; } else if (gpu->glCaps().fragCoordConventionsSupport()) { if (!fSetupFragPosition) { if (gpu->glslGeneration() < k150_GrGLSLGeneration) { this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, "GL_ARB_fragment_coord_conventions"); } fInputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kIn_TypeModifier, "gl_FragCoord", kDefault_GrSLPrecision, GrGLShaderVar::kUpperLeft_Origin); fSetupFragPosition = true; } return "gl_FragCoord"; } else { static const char* kCoordName = "fragCoordYDown"; if (!fSetupFragPosition) { // temporarily change the stage index because we're inserting non-stage code. GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder); SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); const char* rtHeightName; fProgramBuilder->fUniformHandles.fRTHeightUni = fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "RTHeight", &rtHeightName); // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that // causes programs to fail to link. Making this function return a vec2() didn't fix the // problem but using 1.0 for the last two components does. this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, " "1.0);\n", kCoordName, rtHeightName); fSetupFragPosition = true; } SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); return kCoordName; } }
void AutoAway::goIdle() { idle = true; AutoAwayStatus aas(idle, idle_time, this); events_i->fire_event(aas); if(current_settings.enable) { QStringList protos = accounts_i->protocol_names(); foreach(QString proto_name, protos) { QStringList account_ids = accounts_i->account_ids(proto_name); foreach(QString account_id, account_ids) { Account *acc = accounts_i->account_info(proto_name, account_id); if(acc->status != ST_OFFLINE && acc->status != ST_INVISIBLE) { if(current_settings.restore) saved_status[acc] = acc->status; AccountStatusReq asr(acc, current_settings.status, this); events_i->fire_event(asr); } }
nsresult nsDOMWorkerScriptLoader::DoRunLoop(JSContext* aCx) { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); volatile PRBool done = PR_FALSE; mDoneRunnable = new ScriptLoaderDone(this, &done); NS_ENSURE_TRUE(mDoneRunnable, NS_ERROR_OUT_OF_MEMORY); nsresult rv = NS_DispatchToMainThread(this); NS_ENSURE_SUCCESS(rv, rv); while (!(done || mCanceled)) { JSAutoSuspendRequest asr(aCx); NS_ProcessNextEvent(mTarget); } return mCanceled ? NS_ERROR_ABORT : NS_OK; }
bool LuaWrapper::Initialize() { m_luaState = luaL_newstate(); if (m_luaState == nullptr) { return false; } G(m_luaState)->ud = &m_userData; m_userData.m_luaWrapper = this; luaL_openlibs(m_luaState); { StackAutoRecover asr(m_luaState); lua_pushcclosure(m_luaState, luaU_ErrorFunction, 0); m_userData.m_errroFunc = luaL_ref(m_luaState, LUA_REGISTRYINDEX); } return true; }
bool GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); SkASSERT(src); SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the src or dst then we've already succeeded. if (!clip_srcrect_and_dstpoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { SkASSERT(GrDrawTarget::canCopySurface(dst, src, srcRect, dstPoint)); return true; } if (!GrDrawTarget::canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) { return false; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit); this->drawState()->setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX), SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); this->drawState()->addColorTextureProcessor(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(), clippedSrcRect.height()); this->drawSimpleRect(dstRect); return true; }
void execALU(){ switch(controle_alu.op_code){ case 1: add(); break; case 2: addinc(); break; case 3: and(); break; case 4: andnota(); break; case 5: asl(); break; case 6: asr(); break; case 7: deca(); break; case 8: inca(); break; case 9: j(); break; case 10: jal(); break; case 11: jf(); break; case 12: jr(); break; case 13: jt(); break; case 14: lch(); break; case 15: lcl(); break; case 16: load(); break; case 17: loadlit(); break; case 18: lsl(); break; case 19: lsr(); break; case 20: nand(); break; case 21: nor(); break; case 22: ones(); break; case 23: or(); break; case 24: ornotb(); break; case 25: passa(); break; case 26: passnota(); break; case 27: store(); break; case 28: sub(); break; case 29: subdec(); break; case 30: xnor(); break; case 31: xor(); break; case 32: zeros(); break; } }
void GrDrawTarget::clear(const SkIRect* rect, GrColor color, bool canIgnoreRect, GrRenderTarget* renderTarget) { if (fCaps->useDrawInsteadOfClear()) { // This works around a driver bug with clear by drawing a rect instead. // The driver will ignore a clear if it is the only thing rendered to a // target before the target is read. SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height()); if (NULL == rect || canIgnoreRect || rect->contains(rtRect)) { rect = &rtRect; // We first issue a discard() since that may help tilers. this->discard(renderTarget); } AutoStateRestore asr(this, kReset_ASRInit, &SkMatrix::I()); this->drawState()->setColor(color); this->drawState()->disableState(GrDrawState::kClip_StateBit); this->drawState()->disableState(GrDrawState::kHWAntialias_StateBit); this->drawState()->setRenderTarget(renderTarget); this->drawSimpleRect(*rect); } else { this->onClear(rect, color, canIgnoreRect, renderTarget); } }
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { const GrIRect* r = NULL; GrIRect clipRect; GrDrawState* drawState = this->drawState(); const GrRenderTarget* rt = drawState->getRenderTarget(); // GrDrawTarget should have filtered this for us GrAssert(NULL != rt); if (drawState->isClipState()) { GrRect bounds; GrRect rtRect; rtRect.setLTRB(0, 0, GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); if (fClip.hasConservativeBounds()) { bounds = fClip.getConservativeBounds(); if (!bounds.intersect(rtRect)) { bounds.setEmpty(); } } else { bounds = rtRect; } bounds.roundOut(&clipRect); if (clipRect.isEmpty()) { clipRect.setLTRB(0,0,0,0); } r = &clipRect; // use the stencil clip if we can't represent the clip as a rectangle. fClipInStencil = !fClip.isRect() && !fClip.isEmpty() && !bounds.isEmpty(); // TODO: dynamically attach a SB when needed. GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); if (fClipInStencil && NULL == stencilBuffer) { return false; } if (fClipInStencil && stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) { stencilBuffer->setLastClip(fClip, rt->width(), rt->height()); // we set the current clip to the bounds so that our recursive // draws are scissored to them. We use the copy of the complex clip // we just stashed on the SB to render from. We set it back after // we finish drawing it into the stencil. const GrClip& clip = stencilBuffer->getLastClip(); fClip.setFromRect(bounds); AutoStateRestore asr(this); AutoGeometryPush agp(this); drawState->setViewMatrix(GrMatrix::I()); this->flushScissor(NULL); #if !VISUALIZE_COMPLEX_CLIP drawState->enableState(GrDrawState::kNoColorWrites_StateBit); #else drawState->disableState(GrDrawState::kNoColorWrites_StateBit); #endif int count = clip.getElementCount(); int clipBit = stencilBuffer->bits(); SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); clipBit = (1 << (clipBit-1)); bool clearToInside; GrSetOp startOp = kReplace_SetOp; // suppress warning int start = process_initial_clip_elements(clip, rtRect, &clearToInside, &startOp); this->clearStencilClip(clipRect, clearToInside); // walk through each clip element and perform its set op // with the existing clip. for (int c = start; c < count; ++c) { GrPathFill fill; bool fillInverted; // enabled at bottom of loop drawState->disableState(kModifyStencilClip_StateBit); bool canRenderDirectToStencil; // can the clip element be drawn // directly to the stencil buffer // with a non-inverted fill rule // without extra passes to // resolve in/out status. GrPathRenderer* pr = NULL; const GrPath* clipPath = NULL; GrPathRenderer::AutoClearPath arp; if (kRect_ClipType == clip.getElementType(c)) { canRenderDirectToStencil = true; fill = kEvenOdd_PathFill; fillInverted = false; // there is no point in intersecting a screen filling // rectangle. if (kIntersect_SetOp == clip.getOp(c) && clip.getRect(c).contains(rtRect)) { continue; } } else { fill = clip.getPathFill(c); fillInverted = GrIsFillInverted(fill); fill = GrNonInvertedFill(fill); clipPath = &clip.getPath(c); pr = this->getClipPathRenderer(*clipPath, fill); if (NULL == pr) { fClipInStencil = false; fClip = clip; return false; } canRenderDirectToStencil = !pr->requiresStencilPass(this, *clipPath, fill); arp.set(pr, this, clipPath, fill, false, NULL); } GrSetOp op = (c == start) ? startOp : clip.getOp(c); int passes; GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; bool canDrawDirectToClip; // Given the renderer, the element, // fill rule, and set operation can // we render the element directly to // stencil bit used for clipping. canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, clipBit, fillInverted, &passes, stencilSettings); // draw the element to the client stencil bits if necessary if (!canDrawDirectToClip) { GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, kIncClamp_StencilOp, kIncClamp_StencilOp, kAlways_StencilFunc, 0xffff, 0x0000, 0xffff); SET_RANDOM_COLOR if (kRect_ClipType == clip.getElementType(c)) { *drawState->stencil() = gDrawToStencil; this->drawSimpleRect(clip.getRect(c), NULL, 0); } else { if (canRenderDirectToStencil) { *drawState->stencil() = gDrawToStencil; pr->drawPath(0); } else { pr->drawPathToStencil(); } } } // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. drawState->enableState(kModifyStencilClip_StateBit); for (int p = 0; p < passes; ++p) { *drawState->stencil() = stencilSettings[p]; if (canDrawDirectToClip) { if (kRect_ClipType == clip.getElementType(c)) { SET_RANDOM_COLOR this->drawSimpleRect(clip.getRect(c), NULL, 0); } else { SET_RANDOM_COLOR pr->drawPath(0); } } else { SET_RANDOM_COLOR this->drawSimpleRect(bounds, NULL, 0); } } }
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly) { GrMatrix viewM = fTarget->getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds()); // FIXME: It's really dumb that we recreate the verts for a new vertex // layout. We only do that because the GrDrawTarget API doesn't allow // us to change the vertex layout after reserveVertexSpace(). We won't // actually change the vertex data when the layout changes since all the // stages reference the positions (rather than having separate tex coords) // and we don't ever have per-vert colors. In practice our call sites // won't change the stages in use inside a setPath / removePath pair. But // it is a silly limitation of the GrDrawTarget design that should be fixed. if (tol != fPreviousSrcTol || stages != fPreviousStages) { if (!this->createGeom(tol, stages)) { return; } } GrAssert(NULL != fTarget); GrDrawTarget::AutoStateRestore asr(fTarget); bool colorWritesWereDisabled = fTarget->isColorWriteDisabled(); // face culling doesn't make sense here GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawTarget::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (kHairLine_PathFill == fFill) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawTarget::kBoth_DrawFace; } else { if (single_pass_path(*fTarget, *fPath, fFill)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawTarget::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (fFill) { case kInverseEvenOdd_PathFill: reverse = true; // fallthrough case kEvenOdd_PathFill: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace; break; case kInverseWinding_PathFill: reverse = true; // fallthrough case kWinding_PathFill: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawTarget::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawTarget::kCW_DrawFace; drawFace[1] = GrDrawTarget::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: GrAssert(!"Unknown path fFill!"); return; } } } { for (int p = 0; p < passCount; ++p) { fTarget->setDrawFace(drawFace[p]); if (NULL != passes[p]) { fTarget->setStencil(*passes[p]); } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit); } GrRect bounds; if (reverse) { GrAssert(NULL != fTarget->getRenderTarget()); // draw over the whole world. bounds.setLTRB(0, 0, GrIntToScalar(fTarget->getRenderTarget()->width()), GrIntToScalar(fTarget->getRenderTarget()->height())); GrMatrix vmi; // mapRect through persp matrix may not be correct if (!fTarget->getViewMatrix().hasPerspective() && fTarget->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { if (stages) { if (!fTarget->getViewInverse(&vmi)) { GrPrintf("Could not invert matrix."); return; } fTarget->preConcatSamplerMatrices(stages, vmi); } fTarget->setViewMatrix(GrMatrix::I()); } } else { bounds = fPath->getBounds(); bounds.offset(fTranslate); } GrDrawTarget::AutoGeometryPush agp(fTarget); fTarget->drawSimpleRect(bounds, NULL, stages); } else { if (passCount > 1) { fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit); } if (fUseIndexedDraw) { fTarget->drawIndexed(fPrimitiveType, 0, 0, fVertexCnt, fIndexCnt); } else { int baseVertex = 0; for (int sp = 0; sp < fSubpathCount; ++sp) { fTarget->drawNonIndexed(fPrimitiveType, baseVertex, fSubpathVertCount[sp]); baseVertex += fSubpathVertCount[sp]; } } } } } }
//////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, GrTexture** result, GrIRect *devResultBounds) { GrAssert(NULL != devResultBounds); GrAssert(kNone_ClipMaskType == fCurrClipMaskType); if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) { fCurrClipMaskType = kAlpha_ClipMaskType; return true; } // Note: 'resultBounds' is in device (as opposed to canvas) coordinates GrTexture* accum = fAACache.getLastMask(); if (NULL == accum) { fAACache.reset(); return false; } GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); GrDrawState* drawState = fGpu->drawState(); GrDrawTarget::AutoGeometryPush agp(fGpu); // The mask we generate is translated so that its upper-left corner is at devResultBounds // upper-left corner in device space. GrIRect maskResultBounds = GrIRect::MakeWH(devResultBounds->width(), devResultBounds->height()); // Set the matrix so that rendered clip elements are transformed from the space of the clip // stack to the alpha-mask. This accounts for both translation due to the clip-origin and the // placement of the mask within the device. SkVector clipToMaskOffset = { SkIntToScalar(-devResultBounds->fLeft - clipDataIn.fOrigin.fX), SkIntToScalar(-devResultBounds->fTop - clipDataIn.fOrigin.fY) }; drawState->viewMatrix()->setTranslate(clipToMaskOffset); bool clearToInside; SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning SkClipStack::Iter iter(*clipDataIn.fClipStack, SkClipStack::Iter::kBottom_IterStart); const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter, *devResultBounds, &clearToInside, &firstOp, clipDataIn); // The scratch texture that we are drawing into can be substantially larger than the mask. Only // clear the part that we care about. fGpu->clear(&maskResultBounds, clearToInside ? 0xffffffff : 0x00000000, accum->asRenderTarget()); bool accumClearedToZero = !clearToInside; GrAutoScratchTexture temp; bool first = true; // walk through each clip element and perform its set op for ( ; NULL != clip; clip = iter.nextCombined()) { SkRegion::Op op = clip->fOp; if (first) { first = false; op = firstOp; } if (SkRegion::kReplace_Op == op) { // clear the accumulator and draw the new object directly into it if (!accumClearedToZero) { fGpu->clear(&maskResultBounds, 0x00000000, accum->asRenderTarget()); } setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(accum, clip, *devResultBounds); } else if (SkRegion::kReverseDifference_Op == op || SkRegion::kIntersect_Op == op) { // there is no point in intersecting a screen filling rectangle. if (SkRegion::kIntersect_Op == op && NULL != clip->fRect && contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) { continue; } getTemp(*devResultBounds, &temp); if (NULL == temp.texture()) { fAACache.reset(); return false; } // this is the bounds of the clip element in the space of the alpha-mask. The temporary // mask buffer can be substantially larger than the actually clip stack element. We // touch the minimum number of pixels necessary and use decal mode to combine it with // the accumulator GrRect elementMaskBounds = clip->getBounds(); elementMaskBounds.offset(clipToMaskOffset); GrIRect elementMaskIBounds; elementMaskBounds.roundOut(&elementMaskIBounds); // clear the temp target & draw into it fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget()); setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); this->drawClipShape(temp.texture(), clip, elementMaskIBounds); // Now draw into the accumulator using the real operation // and the temp buffer as a texture this->mergeMask(accum, temp.texture(), op, maskResultBounds, elementMaskIBounds); } else { // all the remaining ops can just be directly draw into // the accumulation buffer setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(accum, clip, *devResultBounds); } accumClearedToZero = false; } *result = accum; fCurrClipMaskType = kAlpha_ClipMaskType; return true; }
//////////////////////////////////////////////////////////////////////////////// // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device // (as opposed to canvas) coordinates bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, const GrIRect& devClipBounds) { GrAssert(kNone_ClipMaskType == fCurrClipMaskType); GrDrawState* drawState = fGpu->drawState(); GrAssert(drawState->isClipState()); GrRenderTarget* rt = drawState->getRenderTarget(); GrAssert(NULL != rt); // TODO: dynamically attach a SB when needed. GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); if (NULL == stencilBuffer) { return false; } if (stencilBuffer->mustRenderClip(clipDataIn, rt->width(), rt->height())) { stencilBuffer->setLastClip(clipDataIn, rt->width(), rt->height()); // we set the current clip to the bounds so that our recursive // draws are scissored to them. We use the copy of the complex clip // we just stashed on the SB to render from. We set it back after // we finish drawing it into the stencil. const GrClipData* oldClipData = fGpu->getClip(); // The origin of 'newClipData' is (0, 0) so it is okay to place // a device-coordinate bound in 'newClipStack' SkClipStack newClipStack(devClipBounds); GrClipData newClipData; newClipData.fClipStack = &newClipStack; fGpu->setClip(&newClipData); GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); drawState = fGpu->drawState(); drawState->setRenderTarget(rt); GrDrawTarget::AutoGeometryPush agp(fGpu); if (0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) { // Add the saveLayer's offset to the view matrix rather than // offset each individual draw drawState->viewMatrix()->setTranslate( SkIntToScalar(-clipDataIn.fOrigin.fX), SkIntToScalar(-clipDataIn.fOrigin.fY)); } #if !VISUALIZE_COMPLEX_CLIP drawState->enableState(GrDrawState::kNoColorWrites_StateBit); #endif int clipBit = stencilBuffer->bits(); SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); clipBit = (1 << (clipBit-1)); GrIRect devRTRect = GrIRect::MakeWH(rt->width(), rt->height()); bool clearToInside; SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning SkClipStack::Iter iter(*oldClipData->fClipStack, SkClipStack::Iter::kBottom_IterStart); const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter, devRTRect, &clearToInside, &firstOp, clipDataIn); fGpu->clearStencilClip(devClipBounds, clearToInside); bool first = true; // walk through each clip element and perform its set op // with the existing clip. for ( ; NULL != clip; clip = iter.nextCombined()) { GrPathFill fill; bool fillInverted = false; // enabled at bottom of loop drawState->disableState(GrGpu::kModifyStencilClip_StateBit); // if the target is MSAA then we want MSAA enabled when the clip is soft if (rt->isMultisampled()) { drawState->setState(GrDrawState::kHWAntialias_StateBit, clip->fDoAA); } // Can the clip element be drawn directly to the stencil buffer // with a non-inverted fill rule without extra passes to // resolve in/out status? bool canRenderDirectToStencil = false; SkRegion::Op op = clip->fOp; if (first) { first = false; op = firstOp; } GrPathRenderer* pr = NULL; const SkPath* clipPath = NULL; if (NULL != clip->fRect) { canRenderDirectToStencil = true; fill = kEvenOdd_GrPathFill; fillInverted = false; // there is no point in intersecting a screen filling // rectangle. if (SkRegion::kIntersect_Op == op && contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) { continue; } } else { GrAssert(NULL != clip->fPath); fill = get_path_fill(*clip->fPath); fillInverted = GrIsFillInverted(fill); fill = GrNonInvertedFill(fill); clipPath = clip->fPath; pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true); if (NULL == pr) { fGpu->setClip(oldClipData); return false; } canRenderDirectToStencil = !pr->requiresStencilPass(*clipPath, fill, fGpu); } int passes; GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; bool canDrawDirectToClip; // Given the renderer, the element, // fill rule, and set operation can // we render the element directly to // stencil bit used for clipping. canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, clipBit, fillInverted, &passes, stencilSettings); // draw the element to the client stencil bits if necessary if (!canDrawDirectToClip) { GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, kIncClamp_StencilOp, kIncClamp_StencilOp, kAlways_StencilFunc, 0xffff, 0x0000, 0xffff); SET_RANDOM_COLOR if (NULL != clip->fRect) { *drawState->stencil() = gDrawToStencil; fGpu->drawSimpleRect(*clip->fRect, NULL); } else { if (canRenderDirectToStencil) { *drawState->stencil() = gDrawToStencil; pr->drawPath(*clipPath, fill, fGpu, false); } else { pr->drawPathToStencil(*clipPath, fill, fGpu); } } } // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. drawState->enableState(GrGpu::kModifyStencilClip_StateBit); for (int p = 0; p < passes; ++p) { *drawState->stencil() = stencilSettings[p]; if (canDrawDirectToClip) { if (NULL != clip->fRect) { SET_RANDOM_COLOR fGpu->drawSimpleRect(*clip->fRect, NULL); } else { SET_RANDOM_COLOR pr->drawPath(*clipPath, fill, fGpu, false); } } else { SET_RANDOM_COLOR // 'devClipBounds' is already in device coordinates so the // translation in the view matrix is inappropriate. // Convert it to canvas space so the drawn rect will // be in the correct location GrRect canvClipBounds; canvClipBounds.set(devClipBounds); device_to_canvas(&canvClipBounds, clipDataIn.fOrigin); fGpu->drawSimpleRect(canvClipBounds, NULL); } } }
bool GrTesselatedPathRenderer::onDrawPath(const SkPath& path, GrPathFill fill, const GrVec* translate, GrDrawTarget* target, GrDrawState::StageMask stageMask, bool antiAlias) { GrDrawTarget::AutoStateRestore asr(target); GrDrawState* drawState = target->drawState(); // face culling doesn't make sense here GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); GrMatrix viewM = drawState->getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); GrScalar tolSqd = GrMul(tol, tol); int subpathCnt; int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); GrVertexLayout layout = 0; for (int s = 0; s < GrDrawState::kNumStages; ++s) { if ((1 << s) & stageMask) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } bool inverted = GrIsFillInverted(fill); if (inverted) { maxPts += 4; subpathCnt++; } if (maxPts > USHRT_MAX) { return false; } SkAutoSTMalloc<8, GrPoint> baseMem(maxPts); GrPoint* base = baseMem; GrPoint* vert = base; GrPoint* subpathBase = base; SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt); GrPoint pts[4]; SkPath::Iter iter(path, false); bool first = true; int subpath = 0; for (;;) { switch (iter.next(pts)) { case kMove_PathCmd: if (!first) { subpathVertCount[subpath] = vert-subpathBase; subpathBase = vert; ++subpath; } *vert = pts[0]; vert++; break; case kLine_PathCmd: *vert = pts[1]; vert++; break; case kQuadratic_PathCmd: { GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], tolSqd, &vert, GrPathUtils::quadraticPointCount(pts, tol)); break; } case kCubic_PathCmd: { GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], tolSqd, &vert, GrPathUtils::cubicPointCount(pts, tol)); break; } case kClose_PathCmd: break; case kEnd_PathCmd: subpathVertCount[subpath] = vert-subpathBase; ++subpath; // this could be only in debug goto FINISHED; } first = false; } FINISHED: if (NULL != translate && 0 != translate->fX && 0 != translate->fY) { for (int i = 0; i < vert - base; i++) { base[i].offset(translate->fX, translate->fY); } } if (inverted) { GrRect bounds; GrAssert(NULL != drawState->getRenderTarget()); bounds.setLTRB(0, 0, GrIntToScalar(drawState->getRenderTarget()->width()), GrIntToScalar(drawState->getRenderTarget()->height())); GrMatrix vmi; if (drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop); *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom); *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom); *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop); subpathVertCount[subpath++] = 4; } GrAssert(subpath == subpathCnt); GrAssert((vert - base) <= maxPts); size_t count = vert - base; if (count < 3) { return true; } if (subpathCnt == 1 && !inverted && path.isConvex()) { if (antiAlias) { GrEdgeArray edges; GrMatrix inverse, matrix = drawState->getViewMatrix(); drawState->getViewInverse(&inverse); count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f); size_t maxEdges = target->getMaxEdges(); if (count == 0) { return true; } if (count <= maxEdges) { // All edges fit; upload all edges and draw all verts as a fan target->setVertexSourceToArray(layout, base, count); drawState->setEdgeAAData(&edges[0], count); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); } else { // Upload "maxEdges" edges and verts at a time, and draw as // separate fans for (size_t i = 0; i < count - 2; i += maxEdges - 2) { edges[i] = edges[0]; base[i] = base[0]; int size = GR_CT_MIN(count - i, maxEdges); target->setVertexSourceToArray(layout, &base[i], size); drawState->setEdgeAAData(&edges[i], size); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size); } } drawState->setEdgeAAData(NULL, 0); } else { target->setVertexSourceToArray(layout, base, count); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); } return true; } if (antiAlias) { // Run the tesselator once to get the boundaries. GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fill)); btess.addVertices(base, subpathVertCount, subpathCnt); GrMatrix inverse, matrix = drawState->getViewMatrix(); if (!drawState->getViewInverse(&inverse)) { return false; } if (btess.vertices().count() > USHRT_MAX) { return false; } // Inflate the boundary, and run the tesselator again to generate // interior polys. const GrPointArray& contourPoints = btess.contourPoints(); const GrIndexArray& contours = btess.contours(); GrEdgePolygonTess ptess(contourPoints.count(), GLU_TESS_WINDING_NONZERO, matrix); size_t i = 0; Sk_gluTessBeginPolygon(ptess.tess(), &ptess); for (int contour = 0; contour < contours.count(); ++contour) { int count = contours[contour]; GrEdgeArray edges; int newCount = computeEdgesAndIntersect(matrix, inverse, &btess.contourPoints()[i], count, &edges, 1.0f); Sk_gluTessBeginContour(ptess.tess()); for (int j = 0; j < newCount; j++) { ptess.addVertex(contourPoints[i + j], ptess.vertices().count()); } i += count; Sk_gluTessEndContour(ptess.tess()); } Sk_gluTessEndPolygon(ptess.tess()); if (ptess.vertices().count() > USHRT_MAX) { return false; } // Draw the resulting polys and upload their edge data. drawState->enableState(GrDrawState::kEdgeAAConcave_StateBit); const GrPointArray& vertices = ptess.vertices(); const GrIndexArray& indices = ptess.indices(); const GrDrawState::Edge* edges = ptess.edges(); GR_DEBUGASSERT(indices.count() % 3 == 0); for (int i = 0; i < indices.count(); i += 3) { GrPoint tri_verts[3]; int index0 = indices[i]; int index1 = indices[i + 1]; int index2 = indices[i + 2]; tri_verts[0] = vertices[index0]; tri_verts[1] = vertices[index1]; tri_verts[2] = vertices[index2]; GrDrawState::Edge tri_edges[6]; int t = 0; const GrDrawState::Edge& edge0 = edges[index0 * 2]; const GrDrawState::Edge& edge1 = edges[index0 * 2 + 1]; const GrDrawState::Edge& edge2 = edges[index1 * 2]; const GrDrawState::Edge& edge3 = edges[index1 * 2 + 1]; const GrDrawState::Edge& edge4 = edges[index2 * 2]; const GrDrawState::Edge& edge5 = edges[index2 * 2 + 1]; if (validEdge(edge0) && validEdge(edge1)) { tri_edges[t++] = edge0; tri_edges[t++] = edge1; } if (validEdge(edge2) && validEdge(edge3)) { tri_edges[t++] = edge2; tri_edges[t++] = edge3; } if (validEdge(edge4) && validEdge(edge5)) { tri_edges[t++] = edge4; tri_edges[t++] = edge5; } drawState->setEdgeAAData(&tri_edges[0], t); target->setVertexSourceToArray(layout, &tri_verts[0], 3); target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3); } drawState->setEdgeAAData(NULL, 0); drawState->disableState(GrDrawState::kEdgeAAConcave_StateBit); return true; } GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fill)); ptess.addVertices(base, subpathVertCount, subpathCnt); const GrPointArray& vertices = ptess.vertices(); const GrIndexArray& indices = ptess.indices(); if (indices.count() > 0) { target->setVertexSourceToArray(layout, vertices.begin(), vertices.count()); target->setIndexSourceToArray(indices.begin(), indices.count()); target->drawIndexed(kTriangles_PrimitiveType, 0, 0, vertices.count(), indices.count()); } return true; }
DB asr(DB l, DB r, DB eps, DB res) { DB m = (l+r)/2.0; DB ls = simpson(l, m), rs = simpson(m, r); if (fabs(ls+rs-res) < eps*15) return ls+rs+(ls+rs-res)/15; return asr(l, m, eps/2.0, ls)+asr(m, r, eps/2.0, rs); }
//////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, const GrClip& clipIn, GrTexture** result, GrIRect *resultBounds) { if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) { return true; } GrTexture* accum = fAACache.getLastMask(); if (NULL == accum) { fClipMaskInAlpha = false; fAACache.reset(); return false; } GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); GrDrawState* drawState = gpu->drawState(); GrDrawTarget::AutoGeometryPush agp(gpu); int count = clipIn.getElementCount(); if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { // if we were able to trim down the size of the mask we need to // offset the paths & rects that will be used to compute it GrMatrix m; m.setTranslate(SkIntToScalar(-resultBounds->fLeft), SkIntToScalar(-resultBounds->fTop)); drawState->setViewMatrix(m); } bool clearToInside; SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning int start = process_initial_clip_elements(clipIn, *resultBounds, &clearToInside, &startOp); clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000); GrAutoScratchTexture temp; // walk through each clip element and perform its set op for (int c = start; c < count; ++c) { SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c); if (SkRegion::kReplace_Op == op) { // TODO: replace is actually a lot faster then intersection // for this path - refactor the stencil path so it can handle // replace ops and alter GrClip to allow them through // clear the accumulator and draw the new object directly into it clear(gpu, accum, 0x00000000); setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(gpu, accum, clipIn, c); } else if (SkRegion::kReverseDifference_Op == op || SkRegion::kIntersect_Op == op) { // there is no point in intersecting a screen filling rectangle. if (SkRegion::kIntersect_Op == op && kRect_ClipType == clipIn.getElementType(c) && contains(clipIn.getRect(c), *resultBounds)) { continue; } getTemp(*resultBounds, &temp); if (NULL == temp.texture()) { fClipMaskInAlpha = false; fAACache.reset(); return false; } // clear the temp target & draw into it clear(gpu, temp.texture(), 0x00000000); setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); this->drawClipShape(gpu, temp.texture(), clipIn, c); // TODO: rather than adding these two translations here // compute the bounding box needed to render the texture // into temp if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { GrMatrix m; m.setTranslate(SkIntToScalar(resultBounds->fLeft), SkIntToScalar(resultBounds->fTop)); drawState->preConcatViewMatrix(m); } // Now draw into the accumulator using the real operation // and the temp buffer as a texture setup_boolean_blendcoeffs(drawState, op); this->drawTexture(gpu, accum, temp.texture()); if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { GrMatrix m; m.setTranslate(SkIntToScalar(-resultBounds->fLeft), SkIntToScalar(-resultBounds->fTop)); drawState->preConcatViewMatrix(m); } } else { // all the remaining ops can just be directly draw into // the accumulation buffer setup_boolean_blendcoeffs(drawState, op); this->drawClipShape(gpu, accum, clipIn, c); } } *result = accum; return true; }
//////////////////////////////////////////////////////////////////////////////// // Create a 1-bit clip mask in the stencil buffer bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu, const GrClip& clipIn, const GrRect& bounds, ScissoringSettings* scissorSettings) { GrAssert(fClipMaskInStencil); GrDrawState* drawState = gpu->drawState(); GrAssert(drawState->isClipState()); GrRenderTarget* rt = drawState->getRenderTarget(); GrAssert(NULL != rt); // TODO: dynamically attach a SB when needed. GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); if (NULL == stencilBuffer) { return false; } if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) { stencilBuffer->setLastClip(clipIn, rt->width(), rt->height()); // we set the current clip to the bounds so that our recursive // draws are scissored to them. We use the copy of the complex clip // we just stashed on the SB to render from. We set it back after // we finish drawing it into the stencil. const GrClip& clipCopy = stencilBuffer->getLastClip(); gpu->setClip(GrClip(bounds)); GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); drawState = gpu->drawState(); drawState->setRenderTarget(rt); GrDrawTarget::AutoGeometryPush agp(gpu); gpu->disableScissor(); #if !VISUALIZE_COMPLEX_CLIP drawState->enableState(GrDrawState::kNoColorWrites_StateBit); #endif int count = clipCopy.getElementCount(); int clipBit = stencilBuffer->bits(); SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); clipBit = (1 << (clipBit-1)); GrIRect rtRect = GrIRect::MakeWH(rt->width(), rt->height()); bool clearToInside; SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning int start = process_initial_clip_elements(clipCopy, rtRect, &clearToInside, &startOp); gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside); // walk through each clip element and perform its set op // with the existing clip. for (int c = start; c < count; ++c) { GrPathFill fill; bool fillInverted; // enabled at bottom of loop drawState->disableState(GrGpu::kModifyStencilClip_StateBit); bool canRenderDirectToStencil; // can the clip element be drawn // directly to the stencil buffer // with a non-inverted fill rule // without extra passes to // resolve in/out status. SkRegion::Op op = (c == start) ? startOp : clipCopy.getOp(c); GrPathRenderer* pr = NULL; const SkPath* clipPath = NULL; if (kRect_ClipType == clipCopy.getElementType(c)) { canRenderDirectToStencil = true; fill = kEvenOdd_PathFill; fillInverted = false; // there is no point in intersecting a screen filling // rectangle. if (SkRegion::kIntersect_Op == op && contains(clipCopy.getRect(c), rtRect)) { continue; } } else { fill = clipCopy.getPathFill(c); fillInverted = GrIsFillInverted(fill); fill = GrNonInvertedFill(fill); clipPath = &clipCopy.getPath(c); pr = this->getClipPathRenderer(gpu, *clipPath, fill, false); if (NULL == pr) { fClipMaskInStencil = false; gpu->setClip(clipCopy); // restore to the original return false; } canRenderDirectToStencil = !pr->requiresStencilPass(*clipPath, fill, gpu); } int passes; GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; bool canDrawDirectToClip; // Given the renderer, the element, // fill rule, and set operation can // we render the element directly to // stencil bit used for clipping. canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, clipBit, fillInverted, &passes, stencilSettings); // draw the element to the client stencil bits if necessary if (!canDrawDirectToClip) { GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, kIncClamp_StencilOp, kIncClamp_StencilOp, kAlways_StencilFunc, 0xffff, 0x0000, 0xffff); SET_RANDOM_COLOR if (kRect_ClipType == clipCopy.getElementType(c)) { *drawState->stencil() = gDrawToStencil; gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); } else { if (canRenderDirectToStencil) { *drawState->stencil() = gDrawToStencil; pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); } else { pr->drawPathToStencil(*clipPath, fill, gpu); } } } // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. drawState->enableState(GrGpu::kModifyStencilClip_StateBit); for (int p = 0; p < passes; ++p) { *drawState->stencil() = stencilSettings[p]; if (canDrawDirectToClip) { if (kRect_ClipType == clipCopy.getElementType(c)) { SET_RANDOM_COLOR gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); } else { SET_RANDOM_COLOR pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); } } else { SET_RANDOM_COLOR gpu->drawSimpleRect(bounds, NULL, 0); } } }
//自适应Simpson公式(主过程) double asr(double a, double b, double eps) { return asr (a, b, eps, Simpson (a, b)); }
int main(int argc, const char* argv[]) { std::string opt_ip = "131.254.10.126"; bool opt_language_english = true; bool opt_debug = false; for (unsigned int i=0; i<argc; i++) { if (std::string(argv[i]) == "--ip") opt_ip = argv[i+1]; else if (std::string(argv[i]) == "--fr") opt_language_english = false; else if (std::string(argv[i]) == "--debug") opt_debug = true; else if (std::string(argv[i]) == "--help") { std::cout << "Usage: " << argv[0] << "[--ip <robot address>] [--fr]" << std::endl; return 0; } } std::string camera_name = "CameraTopPepper"; // Open the grabber for the acquisition of the images from the robot vpNaoqiGrabber g; if (! opt_ip.empty()) g.setRobotIp(opt_ip); g.setFramerate(30); g.setCamera(0); g.open(); vpCameraParameters cam = vpNaoqiGrabber::getIntrinsicCameraParameters(AL::kQVGA,camera_name, vpCameraParameters::perspectiveProjWithDistortion); vpHomogeneousMatrix eMc = vpNaoqiGrabber::getExtrinsicCameraParameters(camera_name,vpCameraParameters::perspectiveProjWithDistortion); std::cout << "eMc:" << std::endl << eMc << std::endl; std::cout << "cam:" << std::endl << cam << std::endl; vpNaoqiRobot robot; // Connect to the robot if (! opt_ip.empty()) robot.setRobotIp(opt_ip); robot.open(); if (robot.getRobotType() != vpNaoqiRobot::Pepper) { std::cout << "ERROR: You are not connected to Pepper, but to a different Robot. Check the IP. " << std::endl; return 0; } std::vector<std::string> jointNames_head = robot.getBodyNames("Head"); // Open Proxy for the speech AL::ALTextToSpeechProxy tts(opt_ip, 9559); std::string phraseToSay; if (opt_language_english) { tts.setLanguage("English"); phraseToSay = " \\emph=2\\ Hi,\\pau=200\\ How are you ?"; } else { tts.setLanguage("French"); phraseToSay = " \\emph=2\\ Bonjour,\\pau=200\\ comment vas tu ?"; } // Inizialize PeoplePerception AL::ALPeoplePerceptionProxy people_proxy(opt_ip, 9559); AL::ALMemoryProxy m_memProxy(opt_ip, 9559); people_proxy.subscribe("People", 30, 0.0); std::cout << "period: " << people_proxy.getCurrentPeriod() << std::endl; // Open Proxy for the recognition speech AL::ALSpeechRecognitionProxy asr(opt_ip, 9559); // asr.unsubscribe("Test_ASR"); // return 0 ; asr.setVisualExpression(false); asr.setLanguage("English"); std::vector<std::string> vocabulary; vocabulary.push_back("follow me"); vocabulary.push_back("stop"); // Set the vocabulary asr.setVocabulary(vocabulary,false); // Start the speech recognition engine with user Test_ASR asr.subscribe("Test_ASR"); std::cout << "Speech recognition engine started" << std::endl; // Proxy to control the leds AL::ALLedsProxy led_proxy(opt_ip, 9559); //Declare plots vpPlot * plotter_diff_vel; vpPlot * plotter_vel; vpPlot * plotter_error; vpPlot * plotter_distance; if (opt_debug) { // Plotting plotter_diff_vel = new vpPlot (2); plotter_diff_vel->initGraph(0, 2); plotter_diff_vel->initGraph(1, 2); plotter_diff_vel->setTitle(0, "HeadYaw"); plotter_diff_vel->setTitle(1, "HeadPitch"); plotter_vel= new vpPlot (1); plotter_vel->initGraph(0, 5); plotter_vel->setLegend(0, 0, "vx"); plotter_vel->setLegend(0, 1, "vy"); plotter_vel->setLegend(0, 2, "wz"); plotter_vel->setLegend(0, 3, "q_yaw"); plotter_vel->setLegend(0, 4, "q_pitch"); plotter_error = new vpPlot(1); plotter_error->initGraph(0, 3); plotter_error->setLegend(0, 0, "x"); plotter_error->setLegend(0, 1, "y"); plotter_error->setLegend(0, 2, "Z"); plotter_distance = new vpPlot (1); plotter_distance->initGraph(0, 1); plotter_distance->setLegend(0, 0, "dist"); } try { vpImage<unsigned char> I(g.getHeight(), g.getWidth()); vpDisplayX d(I); vpDisplay::setTitle(I, "ViSP viewer"); vpFaceTrackerOkao face_tracker(opt_ip,9559); double dist = 0.0; // Distance between person detected from peoplePerception and faceDetection // Set Visual Servoing: vpServo task; task.setServo(vpServo::EYEINHAND_L_cVe_eJe) ; task.setInteractionMatrixType(vpServo::CURRENT, vpServo::PSEUDO_INVERSE); // vpAdaptiveGain lambda_adapt; // lambda_adapt.initStandard(1.6, 1.8, 15); vpAdaptiveGain lambda_base(1.2, 1.0, 10); // 2.3, 0.7, 15 vpAdaptiveGain lambda_nobase(5, 2.9, 15); // 4, 0.5, 15 task.setLambda(lambda_base) ; double Z = 0.9; double Zd = 0.9; bool stop_vxy = false; bool move_base = true; bool move_base_prev = true; // Create the desired visual feature vpFeaturePoint s; vpFeaturePoint sd; vpImagePoint ip(I.getHeight()/2, I.getWidth()/2); // Create the current x visual feature vpFeatureBuilder::create(s, cam, ip); vpFeatureBuilder::create(sd, cam, ip); // sd.buildFrom( I.getWidth()/2, I.getHeight()/2, Zd); AL::ALValue limit_yaw = robot.getProxy()->getLimits("HeadYaw"); std::cout << limit_yaw[0][0] << " " << limit_yaw[0][1] << std::endl; // Add the feature task.addFeature(s, sd) ; vpFeatureDepth s_Z, s_Zd; s_Z.buildFrom(s.get_x(), s.get_y(), Z , 0); // log(Z/Z*) = 0 that's why the last parameter is 0 s_Zd.buildFrom(sd.get_x(), sd.get_y(), Zd , 0); // log(Z/Z*) = 0 that's why the last parameter is 0 // Add the feature task.addFeature(s_Z, s_Zd); // Jacobian 6x5 (vx,vy,wz,q_yaq,q_pitch) vpMatrix tJe(6,5); tJe[0][0]= 1; tJe[1][1]= 1; tJe[5][2]= 1; vpMatrix eJe(6,5); double servo_time_init = 0; vpImagePoint head_cog_cur; vpImagePoint head_cog_des(I.getHeight()/2, I.getWidth()/2); vpColVector q_dot; bool reinit_servo = true; unsigned long loop_iter = 0; std::vector<std::string> recognized_names; std::map<std::string,unsigned int> detected_face_map; bool detection_phase = true; unsigned int f_count = 0; // AL::ALValue leg_names = AL::ALValue::array("HipRoll","HipPitch", "KneePitch" ); // AL::ALValue values = AL::ALValue::array(0.0, 0.0, 0.0 ); // robot.getProxy()->setMoveArmsEnabled(false,false); std::vector<std::string> arm_names = robot.getBodyNames("LArm"); std::vector<std::string> rarm_names = robot.getBodyNames("RArm"); std::vector<std::string> leg_names(3); leg_names[0]= "HipRoll"; leg_names[1]= "HipPitch"; leg_names[2]= "KneePitch"; arm_names.insert( arm_names.end(), rarm_names.begin(), rarm_names.end() ); arm_names.insert( arm_names.end(), leg_names.begin(), leg_names.end() ); std::vector<float> arm_values(arm_names.size(),0.0); for (unsigned int i = 0; i < arm_names.size(); i++ ) std::cout << arm_names[i]<< std::endl; robot.getPosition(arm_names, arm_values,false); vpImagePoint best_cog_face_peoplep; bool person_found = false; double t_prev = vpTime::measureTimeSecond(); while(1) { if (reinit_servo) { servo_time_init = vpTime::measureTimeSecond(); t_prev = vpTime::measureTimeSecond(); reinit_servo = false; led_proxy.fadeRGB("FaceLeds","white",0.1); } double t = vpTime::measureTimeMs(); if (0) // (opt_debug) { g.acquire(I); } vpDisplay::display(I); // Detect face bool face_found = face_tracker.detect(); stop_vxy = false; //std::cout << "Loop time face_tracker: " << vpTime::measureTimeMs() - t << " ms" << std::endl; // Check speech recognition result AL::ALValue result_speech = m_memProxy.getData("WordRecognized"); if ( ((result_speech[0]) == vocabulary[0]) && (double (result_speech[1]) > 0.4 )) //move { //std::cout << "Recognized: " << result_speech[0] << "with confidence of " << result_speech[1] << std::endl; task.setLambda(lambda_base) ; move_base = true; } else if ( (result_speech[0] == vocabulary[1]) && (double(result_speech[1]) > 0.4 )) //stop { //std::cout << "Recognized: " << result_speech[0] << "with confidence of " << result_speech[1] << std::endl; task.setLambda(lambda_nobase) ; move_base = false; } if (move_base != move_base_prev) { if (move_base) { phraseToSay = "Ok, I will follow you."; tts.post.say(phraseToSay); } else { phraseToSay = "Ok, I will stop."; tts.post.say(phraseToSay); } } //robot.setStiffness(arm_names,0.0); //robot.getProxy()->setAngles(arm_names,arm_values,1.0); //robot.getProxy()->setAngles("HipRoll",0.0,1.0); //std::cout << "Loop time check_speech: " << vpTime::measureTimeMs() - t << " ms" << std::endl; move_base_prev = move_base; if (face_found) { std::ostringstream text; text << "Found " << face_tracker.getNbObjects() << " face(s)"; vpDisplay::displayText(I, 10, 10, text.str(), vpColor::red); for(size_t i=0; i < face_tracker.getNbObjects(); i++) { vpRect bbox = face_tracker.getBBox(i); if (i == 0) vpDisplay::displayRectangle(I, bbox, vpColor::red, false, 2); else vpDisplay::displayRectangle(I, bbox, vpColor::green, false, 1); vpDisplay::displayText(I, (int)bbox.getTop()-10, (int)bbox.getLeft(), face_tracker.getMessage(i) , vpColor::red); } led_proxy.post.fadeRGB("FaceLeds","blue",0.1); double u = face_tracker.getCog(0).get_u(); double v = face_tracker.getCog(0).get_v(); if (u<= g.getWidth() && v <= g.getHeight()) head_cog_cur.set_uv(u,v); vpRect bbox = face_tracker.getBBox(0); std::string name = face_tracker.getMessage(0); //std::cout << "Loop time face print " << vpTime::measureTimeMs() - t << " ms" << std::endl; } AL::ALValue result = m_memProxy.getData("PeoplePerception/VisiblePeopleList"); //std::cout << "Loop time get Data PeoplePerception " << vpTime::measureTimeMs() - t << " ms" << std::endl; person_found = false; if (result.getSize() > 0) { AL::ALValue info = m_memProxy.getData("PeoplePerception/PeopleDetected"); int num_people = info[1].getSize(); std::ostringstream text; text << "Found " << num_people << " person(s)"; vpDisplay::displayText(I, 10, 10, text.str(), vpColor::red); person_found = true; if (face_found) // Try to find the match between two detection { vpImagePoint cog_face; double dist_min = 1000; unsigned int index_person = 0; for (unsigned int i = 0; i < num_people; i++) { float alpha = info[1][i][2]; float beta = info[1][i][3]; //Z = Zd; // Centre of face into the image float x = g.getWidth()/2 - g.getWidth() * beta; float y = g.getHeight()/2 + g.getHeight() * alpha; cog_face.set_uv(x,y); dist = vpImagePoint::distance(cog_face, head_cog_cur); if (dist < dist_min) { dist_min = dist; best_cog_face_peoplep = cog_face; index_person = i; } } vpDisplay::displayCross(I, best_cog_face_peoplep, 10, vpColor::white); if (dist_min < 55.) { Z = info[1][index_person][1]; // Current distance } } else // Take the first one on the list { float alpha = info[1][0][2]; float beta = info[1][0][3]; //Z = Zd; // Centre of face into the image float x = g.getWidth()/2 - g.getWidth() * beta; float y = g.getHeight()/2 + g.getHeight() * alpha; head_cog_cur.set_uv(x,y); Z = info[1][0][1]; // Current distance } } else { std::cout << "No distance computed " << std::endl; stop_vxy = true; robot.getProxy()->setAngles("HipRoll",0.0,1.0); //Z = Zd; } // float alpha = info[1][0][2]; // float beta = info[1][0][3]; // //Z = Zd; // // Centre of face into the image // float x = g.getWidth()/2 - g.getWidth() * beta; // float y = g.getHeight()/2 + g.getHeight() * alpha; // vpImagePoint cog_face(y,x); // dist = vpImagePoint::distance(cog_face,head_cog_cur); // if (dist < 55.) // Z = info[1][0][1]; // Current distance // else // stop_vxy = true; // } // else // { // std::cout << "No distance computed " << std::endl; // stop_vxy = true; // //Z = Zd; // } //std::cout << "Loop time before VS: " << vpTime::measureTimeMs() - t << " ms" << std::endl; if (face_found || person_found ) { // Get Head Jacobian (6x2) vpMatrix torso_eJe_head; robot.get_eJe("Head",torso_eJe_head); // Add column relative to the base rotation (Wz) // vpColVector col_wz(6); // col_wz[5] = 1; for (unsigned int i = 0; i < 6; i++) for (unsigned int j = 0; j < torso_eJe_head.getCols(); j++) tJe[i][j+3] = torso_eJe_head[i][j]; // std::cout << "tJe" << std::endl << tJe << std::endl; // vpHomogeneousMatrix torsoMHeadPith( robot.getProxy()->getTransform(jointNames_head[jointNames_head.size()-1], 0, true));// get transformation matrix between torso and HeadRoll vpHomogeneousMatrix torsoMHeadPith( robot.getProxy()->getTransform("HeadPitch", 0, true));// get transformation matrix between torso and HeadRoll vpVelocityTwistMatrix HeadPitchVLtorso(torsoMHeadPith.inverse()); for(unsigned int i=0; i< 3; i++) for(unsigned int j=0; j< 3; j++) HeadPitchVLtorso[i][j+3] = 0; //std::cout << "HeadPitchVLtorso: " << std::endl << HeadPitchVLtorso << std::endl; // Transform the matrix eJe = HeadPitchVLtorso *tJe; // std::cout << "eJe" << std::endl << eJe << std::endl; task.set_eJe( eJe ); task.set_cVe( vpVelocityTwistMatrix(eMc.inverse()) ); vpDisplay::displayCross(I, head_cog_des, 10, vpColor::blue); vpDisplay::displayCross(I, head_cog_cur, 10, vpColor::green); // std::cout << "head_cog_des:" << std::endl << head_cog_des << std::endl; // std::cout << "head_cog_cur:" << std::endl << head_cog_cur << std::endl; // Update the current x feature double x,y; vpPixelMeterConversion::convertPoint(cam, head_cog_cur, x, y); s.buildFrom(x, y, Z); //s.set_xyZ(head_cog_cur.get_u(), head_cog_cur.get_v(), Z); // Update log(Z/Z*) feature. Since the depth Z change, we need to update the intection matrix s_Z.buildFrom(s.get_x(), s.get_y(), Z, log(Z/Zd)) ; q_dot = task.computeControlLaw(vpTime::measureTimeSecond() - servo_time_init); //std::cout << "Loop time compute VS: " << vpTime::measureTimeMs() - t << " ms" << std::endl; vpMatrix P = task.getI_WpW(); double alpha = -3.3; double min = limit_yaw[0][0]; double max = limit_yaw[0][1]; vpColVector z_q2 (q_dot.size()); vpColVector q_yaw = robot.getPosition(jointNames_head[0]); z_q2[3] = 2 * alpha * q_yaw[0]/ pow((max - min),2); vpColVector q3 = P * z_q2; //if (q3.euclideanNorm()<10.0) q_dot = q_dot + q3; std::vector<float> vel(jointNames_head.size()); vel[0] = q_dot[3]; vel[1] = q_dot[4]; // Compute the distance in pixel between the target and the center of the image double distance = vpImagePoint::distance(head_cog_cur, head_cog_des); //if (distance > 0.03*I.getWidth()) std::cout << "q:" << std::endl << q_dot << std::endl; // std::cout << "vel" << std::endl << q_dot << std::endl; //std::cout << "distance" << std::endl << distance <<" -- " << 0.03*I.getWidth() << " ++ " << I.getWidth() << std::endl; // if (distance > 0.1*I.getWidth()) robot.setVelocity(jointNames_head,vel); // else // { // std::cout << "Setting hipRoll to zero" << std::endl; // robot.getProxy()->setAngles("HipRoll",0.0,1.0); // } // std::cout << "errorZ: " << task.getError()[2] << std::endl; // std::cout << "stop_vxy: " << stop_vxy << std::endl; if (std::fabs(Z -Zd) < 0.05 || stop_vxy || !move_base) robot.setBaseVelocity(0.0, 0.0, q_dot[2]); else robot.setBaseVelocity(q_dot[0], q_dot[1], q_dot[2]); if (opt_debug) { vpColVector vel_head = robot.getJointVelocity(jointNames_head); for (unsigned int i=0 ; i < jointNames_head.size() ; i++) { plotter_diff_vel->plot(i, 1, loop_iter, q_dot[i+3]); plotter_diff_vel->plot(i, 0, loop_iter, vel_head[i]); } plotter_error->plot(0,loop_iter,task.getError()); plotter_vel->plot(0,loop_iter, q3); plotter_distance->plot(0,0,loop_iter,Z); } // if (detection_phase) // { // //if (score >= 0.4 && distance < 0.06*I.getWidth() && bbox.getSize() > 3000) // if (distance < 0.06*I.getWidth() && bbox.getSize() > 3000) // { // if (opt_debug) // { // vpDisplay::displayRectangle(I, bbox, vpColor::red, false, 1); // vpDisplay::displayText(I, (int)bbox.getTop()-10, (int)bbox.getLeft(), name, vpColor::red); // } // detected_face_map[name]++; // f_count++; // } // else // { // if (opt_debug) // { // vpDisplay::displayRectangle(I, bbox, vpColor::green, false, 1); // vpDisplay::displayText(I, (int)bbox.getTop()-10, (int)bbox.getLeft(), name, vpColor::green); // } // } // if (f_count>10) // { // detection_phase = false; // f_count = 0; // } // } // else // { // std::string recognized_person_name = std::max_element(detected_face_map.begin(), detected_face_map.end(), pred)->first; // unsigned int times = std::max_element(detected_face_map.begin(), detected_face_map.end(), pred)->second; // if (!in_array(recognized_person_name, recognized_names) && recognized_person_name != "Unknown") { // if (opt_language_english) // { // phraseToSay = "\\emph=2\\ Hi \\wait=200\\ \\emph=2\\" + recognized_person_name + "\\pau=200\\ How are you ?"; // } // else // { // phraseToSay = "\\emph=2\\ Salut \\wait=200\\ \\emph=2\\" + recognized_person_name + "\\pau=200\\ comment vas tu ?";; // } // std::cout << phraseToSay << std::endl; // tts.post.say(phraseToSay); // recognized_names.push_back(recognized_person_name); // } // if (!in_array(recognized_person_name, recognized_names) && recognized_person_name == "Unknown" // && times > 15) // { // if (opt_language_english) // { // phraseToSay = "\\emph=2\\ Hi \\wait=200\\ \\emph=2\\. I don't know you! \\emph=2\\ What's your name?"; // } // else // { // phraseToSay = " \\emph=2\\ Salut \\wait=200\\ \\emph=2\\. Je ne te connais pas! \\emph=2\\ Comment t'appelles-tu ?"; // } // std::cout << phraseToSay << std::endl; // tts.post.say(phraseToSay); // recognized_names.push_back(recognized_person_name); // } // detection_phase = true; // detected_face_map.clear(); // } } else { robot.stop(jointNames_head); robot.stopBase(); std::cout << "Stop!" << std::endl; reinit_servo = true; } //if (opt_debug) vpDisplay::flush(I); if (vpDisplay::getClick(I, false)) break; loop_iter ++; std::cout << "Loop time: " << vpTime::measureTimeMs() - t << " ms" << std::endl; } robot.stop(jointNames_head); robot.stopBase(); tts.setLanguage("French"); // tts.exit(); people_proxy.unsubscribe("People"); // people_proxy.exit(); asr.unsubscribe("Test_ASR"); asr.setVisualExpression(true); // asr.exit(); tts.setLanguage("French"); // tts.exit(); led_proxy.fadeRGB("FaceLeds","white",0.1); // led_proxy.exit(); vpDisplay::getClick(I, true); } catch(vpException &e) { std::cout << e.getMessage() << std::endl; } catch (const AL::ALError& e) { std::cerr << "Caught exception " << e.what() << std::endl; } std::cout << "The end: stop the robot..." << std::endl; //tts.setLanguage("French"); // tts.exit(); robot.stop(jointNames_head); robot.stopBase(); return 0; }
// `用自适应Simpson公式计算宽度为w,高度为h的抛物线长` double parabola_arc_length(double w, double h) { a = 4.0*h/(w*w); // `修改全局变量a,从而改变全局函数F的行为` return asr(0, w/2, 1e-5)*2; }
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target, GrDrawTarget::StageBitfield stages, const GrPath& path, GrPathFill fill, const GrPoint* translate, bool stencilOnly) { GrDrawTarget::AutoStateRestore asr(target); bool colorWritesWereDisabled = target->isColorWriteDisabled(); // face culling doesn't make sense here GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace()); GrMatrix viewM = target->getViewMatrix(); // In order to tesselate the path we get a bound on how much the matrix can // stretch when mapping to screen coordinates. GrScalar stretch = viewM.getMaxStretch(); bool useStretch = stretch > 0; GrScalar tol = fCurveTolerance; if (!useStretch) { // TODO: deal with perspective in some better way. tol /= 10; } else { tol = GrScalarDiv(tol, stretch); } GrScalar tolSqd = GrMul(tol, tol); int subpathCnt; int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); GrVertexLayout layout = 0; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if ((1 << s) & stages) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } // add 4 to hold the bounding rect GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0); GrPoint* base = (GrPoint*) arg.vertices(); GrPoint* vert = base; GrPoint* subpathBase = base; GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt); // TODO: use primitve restart if available rather than multiple draws GrPrimitiveType type; int passCount = 0; const GrStencilSettings* passes[3]; GrDrawTarget::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (kHairLine_PathFill == fill) { type = kLineStrip_PrimitiveType; passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawTarget::kBoth_DrawFace; } else { type = kTriangleFan_PrimitiveType; if (single_pass_path(*target, path, fill)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawTarget::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (fill) { case kInverseEvenOdd_PathFill: reverse = true; // fallthrough case kEvenOdd_PathFill: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace; break; case kInverseWinding_PathFill: reverse = true; // fallthrough case kWinding_PathFill: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawTarget::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawTarget::kCW_DrawFace; drawFace[1] = GrDrawTarget::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: GrAssert(!"Unknown path fill!"); return; } } } GrPoint pts[4]; bool first = true; int subpath = 0; SkPath::Iter iter(path, false); for (;;) { GrPathCmd cmd = (GrPathCmd)iter.next(pts); switch (cmd) { case kMove_PathCmd: if (!first) { subpathVertCount[subpath] = vert-subpathBase; subpathBase = vert; ++subpath; } *vert = pts[0]; vert++; break; case kLine_PathCmd: *vert = pts[1]; vert++; break; case kQuadratic_PathCmd: { GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], tolSqd, &vert, GrPathUtils::quadraticPointCount(pts, tol)); break; } case kCubic_PathCmd: { GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], tolSqd, &vert, GrPathUtils::cubicPointCount(pts, tol)); break; } case kClose_PathCmd: break; case kEnd_PathCmd: subpathVertCount[subpath] = vert-subpathBase; ++subpath; // this could be only in debug goto FINISHED; } first = false; } FINISHED: GrAssert(subpath == subpathCnt); GrAssert((vert - base) <= maxPts); if (translate) { int count = vert - base; for (int i = 0; i < count; i++) { base[i].offset(translate->fX, translate->fY); } } // if we're stenciling we will follow with a pass that draws // a bounding rect to set the color. We're stenciling when // passCount > 1. const int& boundVertexStart = maxPts; GrPoint* boundsVerts = base + boundVertexStart; if (lastPassIsBounds) { GrRect bounds; if (reverse) { GrAssert(NULL != target->getRenderTarget()); // draw over the whole world. bounds.setLTRB(0, 0, GrIntToScalar(target->getRenderTarget()->width()), GrIntToScalar(target->getRenderTarget()->height())); GrMatrix vmi; if (target->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } } else { bounds.setBounds((GrPoint*)base, vert - base); } boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); } for (int p = 0; p < passCount; ++p) { target->setDrawFace(drawFace[p]); if (NULL != passes[p]) { target->setStencil(*passes[p]); } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { target->disableState(GrDrawTarget::kNoColorWrites_StateBit); } target->drawNonIndexed(kTriangleFan_PrimitiveType, boundVertexStart, 4); } else { if (passCount > 1) { target->enableState(GrDrawTarget::kNoColorWrites_StateBit); } int baseVertex = 0; for (int sp = 0; sp < subpathCnt; ++sp) { target->drawNonIndexed(type, baseVertex, subpathVertCount[sp]); baseVertex += subpathVertCount[sp]; } } } }
long double asr(long double a, long double b, long double eps) { return asr(a, b, eps, simpson(a, b)); }
long double asr(long double a, long double b, long double eps, long double A) { long double c = a + (b - a) / 2; long double L = simpson(a, c), R = simpson(c, b); if (fabs(L + R - A) < 15 * eps) return L + R + (L + R - A) / 15.; return asr(a, c, eps / 2, L) + asr(c, b, eps / 2, R); }
bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path, const SkStrokeRec& origStroke, GrDrawTarget* target, bool stencilOnly) { SkMatrix viewM = target->getDrawState().getViewMatrix(); SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke); SkScalar hairlineCoverage; if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(), &hairlineCoverage)) { uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * target->getDrawState().getCoverage()); target->drawState()->setCoverage(newCoverage); if (!stroke->isHairlineStyle()) { stroke.writable()->setHairlineStyle(); } } SkScalar tol = SK_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); int vertexCnt; int indexCnt; GrPrimitiveType primType; GrDrawTarget::AutoReleaseGeometry arg; if (!this->createGeom(path, *stroke, tol, target, &primType, &vertexCnt, &indexCnt, &arg)) { return false; } SkASSERT(NULL != target); GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); GrDrawState* drawState = target->drawState(); bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); // face culling doesn't make sense here SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawState::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (stroke->isHairlineStyle()) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(path, *stroke)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (path.getFillType()) { case SkPath::kInverseEvenOdd_FillType: reverse = true; // fallthrough case SkPath::kEvenOdd_FillType: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; break; case SkPath::kInverseWinding_FillType: reverse = true; // fallthrough case SkPath::kWinding_FillType: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawState::kCW_DrawFace; drawFace[1] = GrDrawState::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: SkDEBUGFAIL("Unknown path fFill!"); return false; } } } SkRect devBounds; GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds); for (int p = 0; p < passCount; ++p) { drawState->setDrawFace(drawFace[p]); if (NULL != passes[p]) { *drawState->stencil() = *passes[p]; } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { drawState->disableState(GrDrawState::kNoColorWrites_StateBit); } SkRect bounds; GrDrawState::AutoViewMatrixRestore avmr; if (reverse) { SkASSERT(NULL != drawState->getRenderTarget()); // draw over the dev bounds (which will be the whole dst surface for inv fill). bounds = devBounds; SkMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { avmr.setIdentity(drawState); } } else { bounds = path.getBounds(); } GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit); target->drawSimpleRect(bounds, NULL); } else { if (passCount > 1) { drawState->enableState(GrDrawState::kNoColorWrites_StateBit); } if (indexCnt) { target->drawIndexed(primType, 0, 0, vertexCnt, indexCnt, &devBounds); } else { target->drawNonIndexed(primType, 0, vertexCnt, &devBounds); } } } return true; }