bool CachedExtentRenderer::GetExtent(const Transform &inTransform,Extent2DF &ioExtent,bool inIncludeStroke) { Matrix test = *inTransform.mMatrix; /* Do not normalize for scale ... double norm = test.m00*test.m00 + test.m01*test.m01 + test.m10*test.m10 + test.m11*test.m11; if (norm<=0) return true; norm = 1.0/sqrt(norm); test.m00 *= norm; test.m01 *= norm; test.m10 *= norm; test.m11 *= norm; */ test.mtx = 0; test.mty = 0; int smallest = mExtentCache[0].mID; int slot = 0; for(int i=0;i<3;i++) { CachedExtent &cache = mExtentCache[i]; if (cache.mIsSet && test==cache.mTestMatrix && *inTransform.mScale9==cache.mScale9 && cache.mIncludeStroke==inIncludeStroke) { // Maybe set but not valid - ie, 0 size if (cache.mExtent.Valid()) ioExtent.Add(cache.Get(inTransform)); return true; } if (cache.mID<gCachedExtentID) cache.mID = gCachedExtentID; if (cache.mID<smallest) { smallest = cache.mID; slot = i; } } // Not in cache - fill slot CachedExtent &cache = mExtentCache[slot]; cache.mMatrix = *inTransform.mMatrix; cache.mTestMatrix = test; cache.mScale9 = *inTransform.mScale9; cache.mTransform = inTransform; cache.mTransform.mMatrix = &cache.mMatrix; cache.mTransform.mMatrix3D = &cache.mMatrix; cache.mTransform.mScale9 = &cache.mScale9; cache.mIncludeStroke = inIncludeStroke; cache.mIsSet = true; GetExtent(cache); cache.Get(inTransform); ioExtent.Add(cache.mExtent); return true; }
bool GetExtent(const Transform &inTransform,Extent2DF &ioExtent, bool) { /* printf("In extent %f,%f ... %f,%f\n", ioExtent.mMinX, ioExtent.mMinY, ioExtent.mMaxX, ioExtent.mMaxY ); */ for(int i=0; i<mTileData.size(); i++) { TileData &data= mTileData[i]; for(int c=0; c<4; c++) { UserPoint corner(data.mPos); if (c&1) corner.x += data.mRect.w; if (c&2) corner.y += data.mRect.h; ioExtent.Add( inTransform.mMatrix->Apply(corner.x,corner.y) ); } } /* printf("Got extent %f,%f ... %f,%f\n", ioExtent.mMinX, ioExtent.mMinY, ioExtent.mMaxX, ioExtent.mMaxY ); */ return true; }
bool Render(const RenderTarget &inTarget, const RenderState &inState) { Surface *s = mFill->bitmapData; double bmp_scale_x = 1.0/s->Width(); double bmp_scale_y = 1.0/s->Height(); // Todo:skew bool is_stretch = (inState.mTransform.mMatrix->m00!=1.0 || inState.mTransform.mMatrix->m11!=1.0) && ( inState.mTransform.mMatrix->m00 > 0 && inState.mTransform.mMatrix->m11 > 0 ); for(int i=0; i<mTileData.size(); i++) { TileData &data= mTileData[i]; BlendMode blend = data.mHasColour ? ( mBlendMode==bmAdd ? bmTintedAdd : bmTinted ): mBlendMode; UserPoint corner(data.mPos); UserPoint pos = inState.mTransform.mMatrix->Apply(corner.x,corner.y); if (s->Format()==pfAlpha && !is_stretch && mBlendMode==bmNormal && data.mHasColour /* integer co-ordinate?*/ ) { unsigned int col = inState.mColourTransform->Transform(data.mColour|0xff000000); s->BlitTo(inTarget, data.mRect, (int)(pos.x), (int)(pos.y), blend, 0, col); } else if ( (is_stretch || data.mHasTrans) ) { // Can use stretch if there is no skew and no colour transform... if (!data.mHasColour && (!data.mHasTrans) && mBlendMode==bmNormal ) { UserPoint p0 = pos; pos = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y+data.mRect.h); s->StretchTo(inTarget, data.mRect, DRect(p0.x,p0.y,pos.x,pos.y,true)); } else { int tile_alpha = 256; bool just_alpha = (data.mHasColour) && ((data.mColour&0x00ffffff ) == 0x00ffffff); if (data.mHasColour && mBlendMode==bmNormal) { tile_alpha = data.mColour>>24; if (tile_alpha>0) tile_alpha++; } // Create alpha mask... UserPoint p[4]; p[0] = inState.mTransform.mMatrix->Apply(corner.x,corner.y); if (data.mHasTrans) { p[1] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.w*data.mTransX.x, corner.y + data.mRect.w*data.mTransY.x); p[2] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.w*data.mTransX.x + data.mRect.h*data.mTransX.y, corner.y + data.mRect.w*data.mTransY.x + data.mRect.h*data.mTransY.y ); p[3] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.h*data.mTransX.y, corner.y + data.mRect.h*data.mTransY.y ); } else { p[1] = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y); p[2] = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y+data.mRect.h); p[3] = inState.mTransform.mMatrix->Apply(corner.x,corner.y+data.mRect.h); } Extent2DF extent; extent.Add(p[0]); extent.Add(p[1]); extent.Add(p[2]); extent.Add(p[3]); // Get bounding pixel rect Rect rect = inState.mTransform.GetTargetRect(extent); // Intersect with clip rect ... Rect visible_pixels = rect.Intersect(inState.mClipRect); if (!visible_pixels.HasPixels()) continue; Rect alpha_rect(visible_pixels); bool offscreen_buffer = mBlendMode!=bmNormal; if (offscreen_buffer) { for(int i=0; i<4; i++) { p[i].x -= visible_pixels.x; p[i].y -= visible_pixels.y; } alpha_rect.x -= visible_pixels.x; alpha_rect.y -= visible_pixels.y; } int aa = 1; SpanRect *span = new SpanRect(alpha_rect,aa); for(int i=0; i<4; i++) span->Line00( Fixed10( p[i].x, p[i].y ), Fixed10( p[(i+1)&3].x, p[(i+1)&3].y) ); AlphaMask *alpha = span->CreateMask(inState.mTransform,tile_alpha); delete span; float uvt[6]; uvt[0] = (data.mRect.x) * bmp_scale_x; uvt[1] = (data.mRect.y) * bmp_scale_y; uvt[2] = (data.mRect.x + data.mRect.w) * bmp_scale_x; uvt[3] = (data.mRect.y) * bmp_scale_y; uvt[4] = (data.mRect.x + data.mRect.w) * bmp_scale_x; uvt[5] = (data.mRect.y + data.mRect.h) * bmp_scale_y; mFiller->SetMapping(p,uvt,2); // Can render straight to surface .... if (!offscreen_buffer) { if (s->Format()==pfAlpha) { if (data.mHasColour) { ARGB col = inState.mColourTransform->Transform(data.mColour|0xff000000); mFiller->SetTint(col); } mFiller->Fill(*alpha,0,0,inTarget,inState); } else if (data.mHasTrans && !just_alpha) { ColorTransform buf; RenderState col_state(inState); ColorTransform tint; tint.redMultiplier = ((data.mColour) & 0xff) * one_on_255; tint.greenMultiplier = ((data.mColour>>8) & 0xff) * one_on_255; tint.blueMultiplier = ((data.mColour>>16) & 0xff) * one_on_255; col_state.CombineColourTransform(inState, &tint, &buf); mFiller->Fill(*alpha,0,0,inTarget,col_state); } else mFiller->Fill(*alpha,0,0,inTarget,inState); } else {
bool Render(const RenderTarget &inTarget, const RenderState &inState) { #define orthoTol 1e-6 Surface *s = mFill->bitmapData; double bmp_scale_x = 1.0/s->Width(); double bmp_scale_y = 1.0/s->Height(); bool is_base_ortho = fabs(inState.mTransform.mMatrix->m01)< orthoTol && fabs(inState.mTransform.mMatrix->m10)< orthoTol; float sx = inState.mTransform.mMatrix->m00; float sy = inState.mTransform.mMatrix->m11; bool is_base_identity = is_base_ortho && fabs(sx-1.0)<orthoTol && fabs(sy-1.0)<orthoTol; //int blits = 0; //int stretches = 0; //int renders = 0; for(int i=0;i<mTileData.size();i++) { TileData &data= mTileData[i]; BlendMode blend = data.mHasColour ? ( mBlendMode==bmAdd ? bmTintedAdd : bmTinted ): mBlendMode; UserPoint corner(data.mPos); UserPoint pos = inState.mTransform.mMatrix->Apply(corner.x,corner.y); bool is_ortho = is_base_ortho && (!data.mHasTrans || fabs(data.mTransX.y)<orthoTol); bool is_identity = data.mHasTrans ? is_ortho && fabs(sx*data.mTransX.x-1.0)<orthoTol && fabs(sy*data.mTransY.y-1)<orthoTol : is_base_identity; if ( !is_identity ) { // Can use stretch if there is no skew and no colour transform... if (!data.mHasColour && mBlendMode==bmNormal && is_ortho ) { UserPoint p0 = pos; if (data.mHasTrans) pos = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w*data.mTransX.x, corner.y+data.mRect.h*data.mTransY.y); else pos = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y+data.mRect.h); s->StretchTo(inTarget, data.mRect, DRect(p0.x,p0.y,pos.x,pos.y,true)); //stretches++; } else { //renders++; int tile_alpha = 256; bool just_alpha = (data.mHasColour) && ((data.mColour&0x00ffffff ) == 0x00ffffff); if (data.mHasColour && mBlendMode==bmNormal) { tile_alpha = data.mColour>>24; if (tile_alpha>0) tile_alpha++; } // Create alpha mask... UserPoint p[4]; p[0] = inState.mTransform.mMatrix->Apply(corner.x,corner.y); if (data.mHasTrans) { p[1] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.w*data.mTransX.x, corner.y + data.mRect.w*data.mTransY.x); p[2] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.w*data.mTransX.x + data.mRect.h*data.mTransX.y, corner.y + data.mRect.w*data.mTransY.x + data.mRect.h*data.mTransY.y ); p[3] = inState.mTransform.mMatrix->Apply( corner.x + data.mRect.h*data.mTransX.y, corner.y + data.mRect.h*data.mTransY.y ); } else { p[1] = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y); p[2] = inState.mTransform.mMatrix->Apply(corner.x+data.mRect.w,corner.y+data.mRect.h); p[3] = inState.mTransform.mMatrix->Apply(corner.x,corner.y+data.mRect.h); } Extent2DF extent; extent.Add(p[0]); extent.Add(p[1]); extent.Add(p[2]); extent.Add(p[3]); // Get bounding pixel rect Rect rect = inState.mTransform.GetTargetRect(extent); // Intersect with clip rect ... Rect visible_pixels = rect.Intersect(inState.mClipRect); if (!visible_pixels.HasPixels()) continue; Rect alpha_rect(visible_pixels); bool offscreen_buffer = mBlendMode!=bmNormal; if (offscreen_buffer) { for(int i=0;i<4;i++) { p[i].x -= visible_pixels.x; p[i].y -= visible_pixels.y; } alpha_rect.x -= visible_pixels.x; alpha_rect.y -= visible_pixels.y; } int aa = 1; SpanRect *span = new SpanRect(alpha_rect,aa); // ToImageAA - add 0.5 offset for(int i=0;i<4;i++) span->Line00( Fixed10( p[i].x + 0.5, p[i].y + 0.5 ), Fixed10( p[(i+1)&3].x + 0.5, p[(i+1)&3].y + 0.5) ); AlphaMask *alpha = span->CreateMask(inState.mTransform,tile_alpha); delete span; float uvt[6]; uvt[0] = (data.mRect.x) * bmp_scale_x; uvt[1] = (data.mRect.y) * bmp_scale_y; uvt[2] = (data.mRect.x + data.mRect.w) * bmp_scale_x; uvt[3] = (data.mRect.y) * bmp_scale_y; uvt[4] = (data.mRect.x + data.mRect.w) * bmp_scale_x; uvt[5] = (data.mRect.y + data.mRect.h) * bmp_scale_y; mFiller->SetMapping(p,uvt,2); // Can render straight to surface .... if (!offscreen_buffer) { if (s->Format()==pfAlpha) { if (data.mHasColour) { ARGB col = inState.mColourTransform->Transform(data.mColour|0xff000000); mFiller->SetTint(col); } mFiller->Fill(*alpha,0,0,inTarget,inState); } else if (data.mHasTrans && !just_alpha) { ColorTransform buf; RenderState col_state(inState); ColorTransform tint; tint.redMultiplier = ((data.mColour) & 0xff) * one_on_255; tint.greenMultiplier = ((data.mColour>>8) & 0xff) * one_on_255; tint.blueMultiplier = ((data.mColour>>16) & 0xff) * one_on_255; col_state.CombineColourTransform(inState, &tint, &buf); mFiller->Fill(*alpha,0,0,inTarget,col_state); } else mFiller->Fill(*alpha,0,0,inTarget,inState); } else {