add meshgradient & sweepgradient

This commit is contained in:
侯歌 2021-12-10 11:55:27 +08:00
parent 2101e09ce9
commit 0c9b56f33b
9 changed files with 228 additions and 39 deletions

9
cmake/common_functions.cmake Normal file → Executable file
View File

@ -1,12 +1,13 @@
function(CreatePAK ResourceDIR PakPath) function(CreatePAK ResourceDIR PakPath projectname)
execute_process(COMMAND zip -r -0 ${PakPath} ./ -i * add_custom_command(TARGET ${projectname} PRE_BUILD
COMMAND zip -r -0 ${PakPath} ./
WORKING_DIRECTORY ${ResourceDIR}) WORKING_DIRECTORY ${ResourceDIR})
message("Package ${ResourceDIR} to:${PakPath}") message("Package ${ResourceDIR} to:${PakPath}")
endfunction() endfunction()
function(CreatePO SourceDIR POPath) function(CreatePO SourceDIR POPath projectname)
execute_process( add_custom_command(TARGET ${projectname} PRE_BUILD
COMMAND touch ${POPath} COMMAND touch ${POPath}
COMMAND xgettext -d ntvplus -j -c -p${PROJECT_BINARY_DIR} -kTEXT ${SRCS_NTV_PLUS} COMMAND xgettext -d ntvplus -j -c -p${PROJECT_BINARY_DIR} -kTEXT ${SRCS_NTV_PLUS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}

View File

@ -52,7 +52,7 @@ add_custom_target(systempak
COMMENT "package system resource" COMMENT "package system resource"
) )
CreatePAK(${PROJECT_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/cdroid.pak) CreatePAK(${PROJECT_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/cdroid.pak gui)
set_target_properties(gui_static PROPERTIES OUTPUT_NAME "gui") set_target_properties(gui_static PROPERTIES OUTPUT_NAME "gui")
file(GLOB_RECURSE allfiles RELATIVE "${PROJECT_SOURCE_DIR}/" "*.h") file(GLOB_RECURSE allfiles RELATIVE "${PROJECT_SOURCE_DIR}/" "*.h")

View File

@ -19,6 +19,7 @@
#include <cairomm/pattern.h> #include <cairomm/pattern.h>
#include <cairomm/private.h> #include <cairomm/private.h>
#include <cairomm/matrix.h> #include <cairomm/matrix.h>
#include <math.h>
namespace Cairo namespace Cairo
{ {
@ -287,6 +288,122 @@ RadialGradient::~RadialGradient()
{ {
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MeshPattern::MeshPattern(){
m_cobject=cairo_pattern_create_mesh();
check_object_status_and_throw_exception(*this);
}
MeshPattern::MeshPattern(cairo_pattern_t* cobject, bool has_reference)
:Pattern(cobject,has_reference){
}
void MeshPattern::begin_patch(){
cairo_mesh_pattern_begin_patch(m_cobject);
}
void MeshPattern::end_patch(){
cairo_mesh_pattern_end_patch(m_cobject);
}
void MeshPattern::line_to(double x,double y){
cairo_mesh_pattern_line_to(m_cobject,x,y);
}
void MeshPattern::move_to(double x,double y){
cairo_mesh_pattern_move_to(m_cobject,x,y);
}
void MeshPattern::curve_to(double x1,double y1,double x2,double y2,double x3,double y3){
cairo_mesh_pattern_curve_to(m_cobject,x1,y1,x2,y2,x3,y3);
}
void MeshPattern::set_control_point(uint32_t point_num,double x,double y){
cairo_mesh_pattern_set_control_point(m_cobject,point_num,x,y);
}
void MeshPattern::set_corner_color_rgb(uint32_t corner_num,double red,double green,double blue){
cairo_mesh_pattern_set_corner_color_rgb(m_cobject,corner_num,red,green,blue);
}
void MeshPattern::set_corner_color_rgba(uint32_t corner_num,double red,double green,double blue,double alpha){
cairo_mesh_pattern_set_corner_color_rgba(m_cobject,corner_num,red,green,blue,alpha);
}
int MeshPattern::get_corner_color_rgba(uint32_t patch_num,uint32_t corner_num,double& red,double& green,double& blue,double&alpha){
return cairo_mesh_pattern_get_corner_color_rgba(m_cobject,patch_num,corner_num,&red,&green,&blue,&alpha);
}
int MeshPattern::get_control_point(uint32_t patch_num,uint32_t corner_num,double&x,double&y){
return cairo_mesh_pattern_get_control_point(m_cobject,patch_num,corner_num,&x,&y);
}
RefPtr<MeshPattern>MeshPattern::create(){
cairo_pattern_t*p=cairo_pattern_create_mesh();
return make_refptr_for_instance<MeshPattern>(new MeshPattern());
}
SweepGradient::SweepGradient(double cx,double cy,double radius)
:MeshPattern(){
m_cx=cx;
m_cy=cy;
m_radius=radius;
printf("(%.2f,%.2f:%.2f):%p %p\r\n",m_cx,m_cy,m_radius,this,m_cobject);
}
SweepGradient::SweepGradient(cairo_pattern_t* cobject, bool has_reference)
:MeshPattern(cobject, has_reference){
}
RefPtr<SweepGradient>SweepGradient::create(double cx,double cy,double radius){
return make_refptr_for_instance<SweepGradient>(new SweepGradient(cx,cy,radius));
}
void SweepGradient::add_sector_patch( double angle_A,double A_r, double A_g, double A_b,double A_a,
double angle_B,double B_r, double B_g, double B_b,double B_a){
double r_sin_A, r_cos_A;
double r_sin_B, r_cos_B;
double h;
r_sin_A = m_radius * sin (angle_A);
r_cos_A = m_radius * cos (angle_A);
r_sin_B = m_radius * sin (angle_B);
r_cos_B = m_radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A)/4.0);
begin_patch();
move_to (m_cx, m_cy);
line_to (m_cx + r_cos_A, m_cy + r_sin_A);
curve_to(m_cx + r_cos_A - h * r_sin_A, m_cy + r_sin_A + h * r_cos_A,
m_cx + r_cos_B + h * r_sin_B, m_cy + r_sin_B - h * r_cos_B,
m_cx + r_cos_B, m_cy + r_sin_B);
set_corner_color_rgba (0, 1, 1, 1,A_a);
set_corner_color_rgba (1, A_r, A_g, A_b,A_a);
set_corner_color_rgba (2, B_r, B_g, B_b,B_a);
end_patch ();
}
void SweepGradient::add_sector_patch( double angle_A,double A_r, double A_g, double A_b,
double angle_B,double B_r, double B_g, double B_b){
add_sector_patch(angle_A,A_r,A_g,A_b,1.f,angle_B,B_r,B_g,B_b,1.f);
}
static void color2rgba(uint32_t c,float&r,float&g,float&b,float&a){
a=(c>>24)/255.;
r=((c>>16)&0xFF)/255.;
g=((c>>8)&0xFF)/255.;
b=(c&0xFF)/255;
}
void SweepGradient::add_sector_patch(double angleA,uint32_t colorA,double angleB, uint32_t colorB){
float r1,g1,b1,a1,r2,g2,b2,a2;
color2rgba(colorA,r1,g1,b1,a1);
color2rgba(colorB,r2,g2,b2,a2);
add_sector_patch(angleA,r1,g1,b1,a1,angleB,r2,g2,b2,a2);
}
} //namespace Cairo } //namespace Cairo

View File

@ -79,7 +79,8 @@ public:
/** /**
* The pattern is a radial gradient. * The pattern is a radial gradient.
*/ */
RADIAL = CAIRO_PATTERN_TYPE_RADIAL RADIAL = CAIRO_PATTERN_TYPE_RADIAL,
MESH = CAIRO_PATTERN_TYPE_MESH /*added by zhhou*/
}; };
/** /**
@ -543,6 +544,43 @@ public:
static RefPtr<RadialGradient> create(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1); static RefPtr<RadialGradient> create(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1);
}; };
////////////////////////////////////////////////////////added by zhhou////////////////////////////////////////////////
class CAIROMM_API MeshPattern:public Pattern{
protected:
MeshPattern();
public:
explicit MeshPattern(cairo_pattern_t* cobject, bool has_reference = false);
void begin_patch();
void end_patch();
void line_to(double x,double y);
void move_to(double x,double y);
void curve_to(double,double,double,double,double,double);
void set_control_point(uint32_t point_num,double x,double y);
void set_corner_color_rgb(uint32_t corner_num,double red,double green,double blue);
void set_corner_color_rgba(uint32_t corner_num,double red,double green,double blue,double alpha);
int get_patch_count()const;
int get_corner_color_rgba(uint32_t patch_num,uint32_t corner_num,double& red,double& green,double& blue,double&alpha);
int get_control_point(uint32_t patch_num,uint32_t corner_num,double&x,double&y);
static RefPtr<MeshPattern>create();
};
class CAIROMM_API SweepGradient : public MeshPattern{
private:
double m_cx;
double m_cy;
double m_radius;
protected:
SweepGradient(double,double,double);
public:
explicit SweepGradient(cairo_pattern_t* cobject, bool has_reference = false);
void add_sector_patch( double angle_A,double A_r, double A_g, double A_b,double A_a,
double angle_B,double B_r, double B_g, double B_b,double B_a);
void add_sector_patch( double angle_A,double A_r, double A_g, double A_b,
double angle_B,double B_r, double B_g, double B_b);
void add_sector_patch(double angleA,uint32_t colorA,double angleB,uint32_t colorB);
static RefPtr<SweepGradient> create(double cx,double cy,double r);
};
} // namespace Cairo } // namespace Cairo
#endif //__CAIROMM_PATTERN_H #endif //__CAIROMM_PATTERN_H

View File

@ -33,7 +33,6 @@ bool AnimationDrawable::setVisible(bool visible,bool restart){
void AnimationDrawable::start(){ void AnimationDrawable::start(){
mAnimating = true; mAnimating = true;
LOGD("mRunning=%d",mRunning);
if(!isRunning()) if(!isRunning())
setFrame(0,false,mAnimationState->getChildCount()>1||!mAnimationState->mOneShot); setFrame(0,false,mAnimationState->getChildCount()>1||!mAnimationState->mOneShot);
} }

View File

@ -356,15 +356,6 @@ static void parseShapeGradient(Shape*shape,const AttributeSet&atts){
{"sweep",Shape::Gradient::SWEEP}},Shape::Gradient::LINEAR)); {"sweep",Shape::Gradient::SWEEP}},Shape::Gradient::LINEAR));
if(atts.hasAttribute("gradientRadius")) if(atts.hasAttribute("gradientRadius"))
shape->setGradientRadius(atts.getDimensionPixelSize("gradientRadius")); shape->setGradientRadius(atts.getDimensionPixelSize("gradientRadius"));
std::string type=atts.getString("type");
if(!type.empty()){
switch(type[0]){
case 'l': shape->setGradientType(Shape::Gradient::LINEAR); break; //linear gradient
case 'r': shape->setGradientType(Shape::Gradient::RADIAL); break; //radial gradient
case 's': shape->setGradientType(Shape::Gradient::SWEEP); break; //sweep gradient(not support)
}
}
} }
static void parseCorners(Shape*shape,const AttributeSet&atts){ static void parseCorners(Shape*shape,const AttributeSet&atts){
@ -515,7 +506,7 @@ Drawable*Drawable::fromStream(Context*ctx,std::istream&stream,const std::string&
} while(rdlen); } while(rdlen);
XML_ParserFree(parser); XML_ParserFree(parser);
LOGD("parsed drawable [%p] from %s",pd.drawable,resname.c_str()); LOGV("parsed drawable [%p] from %s",pd.drawable,resname.c_str());
return pd.drawable; return pd.drawable;
} }

View File

@ -103,22 +103,36 @@ void Shape::applyGradients(){
cls.resize(mGradientColors.size()); cls.resize(mGradientColors.size());
for(int i=0;i<mGradientColors.size();i++){ for(int i=0;i<mGradientColors.size();i++){
cls[i]=Color(mGradientColors[i]); cls[i]=Color(mGradientColors[i]);
LOGV("gradient.colors[%d]=%x",i,mGradientColors[i]); LOGV("gradient.colors[%d/%d]=%x",i,mGradientColors.size(),cls[i].toArgb());
} }
RefPtr<Cairo::Gradient> g=std::make_shared<Cairo::Gradient>(mPaint->cobj()); if(mPaint->get_type()!=Pattern::Type::MESH){
switch(mGradientColors.size()){ RefPtr<Cairo::Gradient>pat=std::make_shared<Cairo::Gradient>(mPaint->cobj(),false);
case 2: switch(mGradientColors.size()){
g->add_color_stop_rgba(.0f,cls[0].red(),cls[0].green(),cls[0].blue(),cls[0].alpha()); case 2:
g->add_color_stop_rgba(1.f,cls[1].red(),cls[1].green(),cls[1].blue(),cls[1].alpha()); pat->add_color_stop_rgba(.0f,cls[0].red(),cls[0].green(),cls[0].blue(),cls[0].alpha());
break; pat->add_color_stop_rgba(1.f,cls[1].red(),cls[1].green(),cls[1].blue(),cls[1].alpha());
case 3: break;
g->add_color_stop_rgba(.0f,cls[0].red(),cls[0].green(),cls[0].blue(),cls[0].alpha()); case 3:
g->add_color_stop_rgba(.5f,cls[1].red(),cls[1].green(),cls[1].blue(),cls[1].alpha()); pat->add_color_stop_rgba(.0f,cls[0].red(),cls[0].green(),cls[0].blue(),cls[0].alpha());
g->add_color_stop_rgba(1.f,cls[2].red(),cls[2].green(),cls[2].blue(),cls[2].alpha()); pat->add_color_stop_rgba(.5f,cls[1].red(),cls[1].green(),cls[1].blue(),cls[1].alpha());
pat->add_color_stop_rgba(1.f,cls[2].red(),cls[2].green(),cls[2].blue(),cls[2].alpha());
break; break;
}
}else{
RefPtr<Cairo::SweepGradient>swp=std::dynamic_pointer_cast<Cairo::SweepGradient>(mPaint);
const uint32_t*cc=mGradientColors.data();
const size_t ccnum=mGradientColors.size();
double angle=0;
for(int i=0;i<ccnum;i++){
swp->add_sector_patch(angle,mGradientColors[i],angle+M_PI*2./ccnum,mGradientColors[(i+1)%ccnum]);
LOGV("add_sector_patch(%.2f) color:%x->%x",angle,mGradientColors[i],mGradientColors[(i+1)%ccnum]);
angle+=M_PI*2./ccnum;
}
} }
} }
void Shape::rebuildPattern(int x,int y){ void Shape::rebuildPattern(int x,int y){
const float cx=mGradientCenterX*mWidth+x;
const float cy=mGradientCenterY*mHeight+y;
switch(mGradientType){ switch(mGradientType){
case Gradient::SOLID:{ case Gradient::SOLID:{
const Color c(mGradientColors[0]); const Color c(mGradientColors[0]);
@ -128,26 +142,29 @@ void Shape::rebuildPattern(int x,int y){
const int angleIndex=mGradientAngle/45; const int angleIndex=mGradientAngle/45;
const int wh=std::max(mWidth,mHeight); const int wh=std::max(mWidth,mHeight);
switch(angleIndex%8){ switch(angleIndex%8){
case 0: mPaint=LinearGradient::create(0,0,wh,0) ; break; case 0: mPaint=LinearGradient::create(0,0,mWidth,0) ; break;
case 1: mPaint=LinearGradient::create(0,wh,wh,0); break; case 1: mPaint=LinearGradient::create(0,wh,wh,0); break;
case 2: mPaint=LinearGradient::create(0,wh,0,0) ; break; case 2: mPaint=LinearGradient::create(0,mHeight,0,0) ; break;
case 3: mPaint=LinearGradient::create(wh,wh,0,0); break; case 3: mPaint=LinearGradient::create(wh,wh,0,0); break;
case 4: mPaint=LinearGradient::create(wh,0,0,0) ; break; case 4: mPaint=LinearGradient::create(mWidth,0,0,0) ; break;
case 5: mPaint=LinearGradient::create(wh,0,0,wh); break; case 5: mPaint=LinearGradient::create(wh,0,0,wh); break;
case 6: mPaint=LinearGradient::create(0,0,0,wh) ; break; case 6: mPaint=LinearGradient::create(0,0,0,mHeight) ; break;
case 7: mPaint=LinearGradient::create(0,0,wh,wh); break; case 7: mPaint=LinearGradient::create(0,0,wh,wh); break;
} }
LOGV("angleIndex=%d size=%dx%d %d colors",angleIndex,mWidth,mHeight,mGradientColors.size());
applyGradients(); applyGradients();
}break; }break;
case Gradient::RADIAL:{ case Gradient::RADIAL:{
const float cx=mGradientCenterX*mWidth+x;
const float cy=mGradientCenterY*mHeight+y;
const float pd=mGradientAngle*M_PI/180.f; const float pd=mGradientAngle*M_PI/180.f;
LOGV("center=%.2f,%.2f cx,cy=%.2f,%.2f mRadius=%f mAngle=%.2f xy=%d,%d",mGradientCenterX,mGradientCenterY,cx,cy,mGradientRadius,mGradientAngle,x,y); LOGV("center=%.2f,%.2f cx,cy=%.2f,%.2f mRadius=%f mAngle=%.2f xy=%d,%d",mGradientCenterX,mGradientCenterY,cx,cy,mGradientRadius,mGradientAngle,x,y);
mPaint=RadialGradient::create(cx,cy,0,cx,cy,mGradientRadius); mPaint=RadialGradient::create(cx,cy,0,cx,cy,mGradientRadius);
applyGradients(); applyGradients();
}break; }break;
case Gradient::SWEEP: case Gradient::SWEEP:{
mPaint=SweepGradient::create(mGradientCenterX*mWidth,mGradientCenterY*mHeight,mGradientRadius);
LOGV("SWEEP(%.2f,%.2f:%.2f",mGradientCenterX*mWidth,mGradientCenterY*mHeight,mGradientRadius);
applyGradients();
}break;
default: default:
LOGE("unsupported gradient type %d",mGradientType); LOGE("unsupported gradient type %d",mGradientType);
break; break;
@ -158,7 +175,8 @@ void Shape::fill_stroke(Canvas&canvas,int x,int y){
const bool bstroke=(mStrokeWidth>0) && (mStrokeColor&0x80000000); const bool bstroke=(mStrokeWidth>0) && (mStrokeColor&0x80000000);
if(mGradientColors.size()){ if(mGradientColors.size()){
rebuildPattern(x,y); rebuildPattern(x,y);
mPaint->set_matrix(canvas.get_matrix()); if(mGradientType==Shape::Gradient::RADIAL)
mPaint->set_matrix(canvas.get_matrix());
canvas.set_source(mPaint); canvas.set_source(mPaint);
if(bstroke) if(bstroke)
canvas.fill_preserve(); canvas.fill_preserve();
@ -202,7 +220,7 @@ void RectShape::onResize(int width,int height){
} }
void RectShape::draw(Canvas&canvas,int x,int y){ void RectShape::draw(Canvas&canvas,int x,int y){
if(mPaint)canvas.set_source(mPaint); rebuildPattern(x,y);
canvas.rectangle(0,0,mWidth,mHeight); canvas.rectangle(0,0,mWidth,mHeight);
fill_stroke(canvas,x,y); fill_stroke(canvas,x,y);
} }
@ -292,8 +310,8 @@ void OvalShape::draw(Canvas&canvas,int x,int y){
canvas.scale(1.f/ratio,1.f); canvas.scale(1.f/ratio,1.f);
canvas.set_fill_rule(Cairo::Context::FillRule::EVEN_ODD); canvas.set_fill_rule(Cairo::Context::FillRule::EVEN_ODD);
} }
fill_stroke(canvas,x,y);
canvas.translate(-mWidth/2,-mHeight/2); canvas.translate(-mWidth/2,-mHeight/2);
fill_stroke(canvas,x,y);
} }
RoundRectShape::RoundRectShape():RectShape(){ RoundRectShape::RoundRectShape():RectShape(){
@ -345,6 +363,7 @@ void RoundRectShape::drawRound(Canvas&canvas,const Rect&r,const std::vector<floa
void RoundRectShape::draw(Canvas&canvas,int x,int y){ void RoundRectShape::draw(Canvas&canvas,int x,int y){
Rect r={0,0,mWidth,mHeight}; Rect r={0,0,mWidth,mHeight};
drawRound(canvas,r,mOuterRadii); drawRound(canvas,r,mOuterRadii);
canvas.set_fill_rule(Cairo::Context::FillRule::WINDING);
if(mInnerRadii.size()){ if(mInnerRadii.size()){
drawRound(canvas,r,mInnerRadii); drawRound(canvas,r,mInnerRadii);
canvas.set_fill_rule(Cairo::Context::FillRule::EVEN_ODD); canvas.set_fill_rule(Cairo::Context::FillRule::EVEN_ODD);

View File

@ -196,7 +196,11 @@ Drawable*ShapeDrawable::inflate(Context*ctx,const AttributeSet&atts){
oval->setThicknessRatio(atts.getFloat("thicknessRatio",.0f)); oval->setThicknessRatio(atts.getFloat("thicknessRatio",.0f));
oval->setInnerRadius(atts.getInt("innerRadius",0)); oval->setInnerRadius(atts.getInt("innerRadius",0));
oval->setInnerRadiusRatio(atts.getFloat("innerRadiusRatio",.0f)); oval->setInnerRadiusRatio(atts.getFloat("innerRadiusRatio",.0f));
}else if(type.compare( "arc")==0) shape = new ArcShape(0,0); }else if(type.compare( "arc")==0){
const float start=atts.getFloat("startAngle",0);
const float end =atts.getFloat("endAngle",360);
shape= new ArcShape(start,end);
}
ShapeDrawable*d=new ShapeDrawable(); ShapeDrawable*d=new ShapeDrawable();
d->setShape(shape); d->setShape(shape);
return d; return d;

View File

@ -171,6 +171,26 @@ TEST_F(DRAWABLE,rectshape){
} }
} }
TEST_F(DRAWABLE,roundrect){
RECT rect={2,2,2,2};
std::vector<float>out={40,30,50,30};
std::vector<float>in={};//{30,20,30,20};
RoundRectShape*rs=new RoundRectShape(out,rect,in);
rs->setStrokeColor(0xFFFF0000);
rs->setGradientColors(std::vector<uint32_t>{0xFFFF0000,0xFF00FF00});//,0xFF0000FF});
rs->setGradientType(Shape::Gradient::SWEEP);
rs->setGradientAngle(270);
rs->setStrokeSize(5);
rs->setGradientCenterX(.5f);
rs->setGradientCenterY(.5f);
rs->setGradientRadius(250);
rs->resize(500,500);
ctx->set_color(0xFF00FF00);
rs->draw(*ctx,50,50);
postCompose();
sleep(10);
}
TEST_F(DRAWABLE,roundrectshape){ TEST_F(DRAWABLE,roundrectshape){
RECT rect={2,2,2,2}; RECT rect={2,2,2,2};
std::vector<float>out={40,30,50,30}; std::vector<float>out={40,30,50,30};