Windows编译skia

Win10(VS2019/2017,python2.7,翻墙):

  1. depot_tools:
  1. ninja:
  • 下载至任意位置并添加至环境变量PATH:git clone git://github.com/ninja-build/ninja.git
  • 进入ninja文件夹,执行python configure.py --bootstrap (确保python执行python2.7)
  1. skia:
  • skia目前貌似不能直接git clone https://skia.googlesource.com/skia.git 需要点开https://skia.googlesource.com/skia.git这个链接,手动点击左侧branches里的master进行下载
  • 上述下载中,如果翻墙了仍然有超时问题,考虑有可能是git没有走ss端口:
    • git config --global http.proxy socks5://127.0.0.1:1087
    • git config --global https.proxy socks5://127.0.0.1:1087
  1. 用gn工具构建工程:
  • 首先修改 skia\gn\BUILDCONFIG.gn文件 win_vc = "C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/VC",如果是vs2019则应该是"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC" 具体取决于安装路径
  • 然后进入skia文件夹,cmd中:
    • gn gen out/Static构建静态库
    • gn gen out/Debug构建Debug版本
    • gn gen out/Release --args="is_debug=false" 构建Release版本
    • 也可以gn gen out/sln --ide=vs,会构建出out/sln解决方案目录,但是有可能无法正确生成,尽量不要使用这个
  1. 用ninja工具生成可执行或库:
  • ninja -C out/Static
  • ninja -C out/Release
  • ninja -C out/Debug
  1. 在vs项目中使用skia:
  • 新建项目,配置选择为release x64,附加包含目录需要包括了skia的include和src文件夹,如项目下有myInclude作为附加包含目录,则将skia中的include和src文件夹平行复制进myInclude。附加依赖库主要需要skia.lib,在out/Static里,以及其他有可能需要的lib文件如icu.lib等
  • 由于skia不负责具体的渲染,需要有opengl等,因此简单地测试skia的绘制效果需要将其作为图片存下来看效果。实例代码如下:
#include "include/core/SkBitmap.h"
//#include "include/codec/SkDevice.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRect.h"
#include "include/core/SkImageEncoder.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkFont.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkPath.h"

const char* pText = "Hello world!";

int main()
{
        const int width = 1000;
        const int height = 1000;

        SkBitmap bitmap;
        SkImageInfo ii = SkImageInfo::Make(1000,1000, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
        bitmap.allocPixels(ii, ii.minRowBytes());

        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setColor(0xff1f78b4);
        paint.setStrokeWidth(8);

        bitmap.allocPixels();
        SkCanvas canvas(bitmap);
        canvas.clear(0x00000000);// 背景为透明色

        if(0){
                SkRect rc;
                rc.fLeft = 123;
                rc.fTop = 0;
                rc.fRight = 222;
                rc.fBottom = 50;
                canvas.drawOval(rc, paint);
        }

        if (0) {
                //测试奇偶填充效果1
                SkPath path;

                path.addCircle(200, 200, 70);
                path.addCircle(300, 200, 70);
                path.addCircle(250, 250, 70);

                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kFill_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
        }
        if (0) {
                //测试奇偶填充效果2
                SkPath path, path1, path2, path3;
                SkPoint pt[11];
                pt[0] = SkPoint::Make(200, 400);
                pt[1] = SkPoint::Make(400, 300);
                pt[2] = SkPoint::Make(600, 300);
                pt[3] = SkPoint::Make(800, 400);
                pt[4] = SkPoint::Make(700, 800);
                pt[5] = SkPoint::Make(600, 600);
                pt[6] = SkPoint::Make(500, 600);
                pt[7] = SkPoint::Make(500, 400);
                pt[8] = SkPoint::Make(600, 300);
                pt[9] = SkPoint::Make(800, 200);

                
                //一条完整path
                if (0) {
                        path.moveTo(pt[0]);
                        path.cubicTo(pt[1], pt[2], pt[3]);
                        path.cubicTo(pt[4], pt[5], pt[6]);
                        path.cubicTo(pt[7], pt[8], pt[9]);
                        path.lineTo(pt[3]);
                }

                //三条path加进去
                if (1) {
                        path1.moveTo(pt[0]).cubicTo(pt[1], pt[2], pt[3]);
                        path2.moveTo(pt[3]).cubicTo(pt[4], pt[5], pt[6]);
                        path3.moveTo(pt[6]).cubicTo(pt[7], pt[8], pt[9]);
                        path.addPath(path1).addPath(path2).addPath(path3);
                }

                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kStrokeAndFill_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
        }

        if (0) {
                //测试winding填充效果
                //两个矩形,顺逆时针
                SkPath path, path1, path2, path3;
                SkPoint pt[8];
                pt[0] = SkPoint::Make(200, 500);
                pt[1] = SkPoint::Make(400, 300);
                pt[2] = SkPoint::Make(600, 500);
                pt[3] = SkPoint::Make(400, 700);
                pt[4] = SkPoint::Make(400, 500);
                pt[5] = SkPoint::Make(600, 300);
                pt[6] = SkPoint::Make(800, 500);
                pt[7] = SkPoint::Make(600, 700);


                //顺时针path
                path1.moveTo(pt[0]).lineTo(pt[1]).lineTo(pt[2]).lineTo(pt[3]).close();

                //逆时针path
                path2.moveTo(pt[4]).lineTo(pt[7]).lineTo(pt[6]).lineTo(pt[5]).close();

                path.addPath(path1).addPath(path2);

                path.setFillType(SkPathFillType::kWinding);

                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kFill_Style);
                //paint.setStyle(SkPaint::kStroke_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
        }

        if (0) {
                //测试不闭合path绘制问题
                SkPath path, path1, path2, path3;
                SkPoint pt[6];
                pt[0] = SkPoint::Make(300, 200);
                pt[1] = SkPoint::Make(500, 200);
                pt[2] = SkPoint::Make(200, 500);
                pt[3] = SkPoint::Make(600, 500);
                pt[4] = SkPoint::Make(200, 700);
                pt[5] = SkPoint::Make(600, 700);


                path.moveTo(pt[0]).lineTo(pt[5]);
                path.moveTo(pt[1]).lineTo(pt[4]); //path1.moveTo(pt[1]).lineTo(pt[4]);
                path.moveTo(pt[2]).lineTo(pt[3]); //path2.moveTo(pt[1]).lineTo(pt[4]);


                //path.addPath(path1).addPath(path2);

                path.setFillType(SkPathFillType::kWinding);

                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kStrokeAndFill_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
        }

        if (1) {
                //测试不闭合path绘制问题2
                SkPath path, path1, path2, path3;
                SkPoint pt[6];
                pt[0] = SkPoint::Make(200, 200);
                pt[1] = SkPoint::Make(400, 200);
                pt[2] = SkPoint::Make(600, 200);
                pt[3] = SkPoint::Make(200, 600);
                pt[4] = SkPoint::Make(400, 600);
                pt[5] = SkPoint::Make(600, 600);

                path.moveTo(pt[0]).lineTo(pt[4]).lineTo(pt[2]);
                path1.moveTo(pt[3]).lineTo(pt[1]).lineTo(pt[5]);

                path.setFillType(SkPathFillType::kWinding);
                path1.setFillType(SkPathFillType::kWinding);

                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kStrokeAndFill_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
                canvas.drawPath(path1, paint);
        }

        if(0){
        //画贝塞尔曲线
                 SkPath path;
                 SkPoint pt[20];
 
                 pt[0].set(100, 100);
                 pt[1].set(200, 80);
                 pt[2].set(300, 80);
                 pt[3].set(400, 100);

                pt[4].set(300, 200);
                pt[5].set(200, 300);
                pt[6].set(100, 300);
                

                 path.moveTo(pt[0]);
                 //二次贝塞尔曲线
                 //path.quadTo(pt1, pt2);
                 //三次贝塞尔曲线
                 path.cubicTo(pt[1], pt[2], pt[3]);
                path.cubicTo(pt[4], pt[5], pt[6]);

                //path.moveTo(pt[0]);
                //path.lineTo(pt[3]);
                //path.close();
                 paint.setAntiAlias(true);//抗锯齿
                 paint.setStyle(SkPaint::kFill_Style);
                 paint.setStrokeWidth(1);
                 paint.setColor(SK_ColorBLACK);
                 canvas.drawPath(path, paint);
                 //贝塞尔点
                 paint.setColor(SK_ColorRED);
                 canvas.drawCircle(pt[0].x(), pt[0].y(), 4, paint);
                 canvas.drawCircle(pt[1].x(), pt[1].y(), 4, paint);
                 canvas.drawCircle(pt[2].x(), pt[2].y(), 4, paint);
                 canvas.drawCircle(pt[3].x(), pt[3].y(), 4, paint);
        }

        if(0){
                //画弧线
                SkPath path;
                SkPoint pt1, pt2, pt_ctrl;
                SkPaint paint;
                pt1.set(100, 100);
                pt_ctrl.set(180, 250);
                pt2.set(300, 300);
                for (float i = 1; i < 20; i += 1) {
                        SkPath tmp;
                        tmp.moveTo(pt1);
                        tmp.conicTo(pt_ctrl, pt2, i);
                        path.addPath(tmp);
                }
                path.close();
                paint.setAntiAlias(true);//抗锯齿
                paint.setStyle(SkPaint::kStroke_Style);
                paint.setStrokeWidth(1);
                paint.setColor(SK_ColorBLACK);
                canvas.drawPath(path, paint);
        }

        SkFILEWStream stream("./test.jpg");
        SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);


        return 0;
}

Linux&MacOS:

1.安装dev_tools

skia库编译需要依赖google发布的dev_tools编译环境

下载地址: git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'

(目前git已经无法直接clone下来,需要点开https://chromium.googlesource.com/chromium/tools/depot_tools这个链接,手动点击左侧branches里的master进行下载)

环境变量: export PATH={PWD}/depot_tools:{PATH}

配置好环境变量后输入gn 和ninja,测试是否效

2.下载源码并编译

skia源码下载:git clone https://skia.googlesource.com/skia.git

(skia目前貌似不能直接git clone 需要点开https://skia.googlesource.com/skia.git这个链接,手动点击左侧branches里的master进行下载)

安装编译依赖:cd skia && python2 tools/git-sync-deps (注:需要python2.7环境)

编译安装skia

使用 gn工具生成输出目录及编译配置参数

如:bin/gn gen out/Debug (使用默认配置输出到out/Debug目录)

bin/gn gen out/Release --args='is_debug=false'(禁用Debug模式输出到out/Release目录)

还可以通过设置编译器版本等,具体参见help指令和官方wiki

bin/gn args out/Debug --list (可以查看配置所有的参数)

执行编译 ninja -C out/Debug (过程比较漫长,可以喝杯咖啡或去做下面事情) (此过程会直接调用python命令,通过软链接或者重命名方式确保python命令调用python2)

输出结果:

image

上面会输出编译后所有生成的目标库及sample程序, 尝试运行HelloWorld

image

3. 添加扩展模块

我们根据samle程序里面提供的HelloWorld修改一个我们自己的HelloWorld程序

  1. 打开根目录下BUILD.gn找到test_app("HelloWorld"),拷贝复制HelloWorld程序
image
image
  1. 在example目录下copy HelloWorld.h HelloWorld.cpp到HelloWorld.h HelloWorld.cpp
  2. 重新执行bin/gn gen out/Debug生成编译配置
  3. 执行ninja -C out/Debug HelloWorld 指定编译HelloWorld模块, 生成并运行./out/Debug/HelloWorld
image
image
  1. 可以根据自己的需求封装自己的工程模块或修改skia提供的modules

  2. Flatbuffers类库(https://google.github.io/flatbuffers/

2.1 安装编译工具cmake

mac平台可使用brew install cmake安装

ubuntu环境可以使用sudo apt-get install cmake

或者去https://cmake.org/下载安装

2.2 下载源码并编译

源码下载:https://github.com/google/flatbuffers.git

编译安装:cmake . 生成makefile,后执行make 编译

编译后生成flac和libflatbuffers.a

2.3 简单sample程序

编写MyGame.fbs文件

// Example IDL file for our monster's schema.

namespace MyGame.Sample;

enum Color:byte { Red = 0, Green, Blue = 2 }

union Equipment { Weapon } // Optionally add more tables.

struct Vec3 {

x:float;

y:float;

z:float;

}

table Monster {

pos:Vec3; // Struct.

mana:short = 150;

hp:short = 100;

name:string;

friendly:bool = false (deprecated);

inventory:[ubyte]; // Vector of scalars.

color:Color = Blue; // Enum.

weapons:[Weapon]; // Vector of tables.

equipped:Equipment; // Union.

path:[Vec3]; // Vector of structs.

}

table Weapon {

name:string;

damage:short;

}

root_type Monster;

使用2.2生成的flatc生成目标代码 flatc --cpp MyGame.fbs生成MyGame_generated.h

编写C++代码来使用fb

#include <iostream>

#include <fstream>

#include <vector>

#include "MyGame_generated.h"

#include "flatbuffers/flatbuffers.h"

using namespace MyGame::Sample;

int main(/*int argc, char* argv[]*/)

{

flatbuffers::FlatBufferBuilder builder;

auto weapon_one_name = builder.CreateString("Sword");

short weapon_one_damage = 3;

auto weapon_two_name = builder.CreateString("Axe");

short weapon_two_damage = 5;

auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage);

auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage);

std::vector<flatbuffers::Offset<Weapon>> weapons_vector;

weapons_vector.push_back(sword);

weapons_vector.push_back(axe);

auto weapons = builder.CreateVector(weapons_vector);

auto position = Vec3(1.0f, 2.0f, 3.0f);

auto name = builder.CreateString("MyMonster");

unsigned char inv_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

auto inventory = builder.CreateVector(inv_data, 10);

auto orc = CreateMonster(builder, &position, 150, 80, name, inventory,

Color_Red, weapons, Equipment_Weapon, axe.Union());

builder.Finish(orc); // Serialize the root of the object.

auto monster = GetMonster(builder.GetBufferPointer());

assert(monster->hp() == 80);

assert(monster->mana() == 150); // default

assert(monster->name()->str() == "MyMonster");

auto pos = monster->pos();

assert(pos);

assert(pos->z() == 3.0f);

(void)pos;

auto inv = monster->inventory();

assert(inv);

assert(inv->Get(9) == 9);

(void)inv;

std::string expected_weapon_names[] = {"Sword", "Axe"};

short expected_weapon_damages[] = {3, 5};

auto weps = monster->weapons();

for (unsigned int i = 0; i < weps->size(); i++)

{

assert(weps->Get(i)->name()->str() == expected_weapon_names[i]);

assert(weps->Get(i)->damage() == expected_weapon_damages[i]);

}

(void)expected_weapon_names;

(void)expected_weapon_damages;

assert(monster->equipped_type() == Equipment_Weapon);

auto equipped = static_cast<const Weapon *>(monster->equipped());

assert(equipped->name()->str() == "Axe");

assert(equipped->damage() == 5);

(void)equipped;

printf("The FlatBuffer was successfully created and verified!\n");

return 0;

}
  1. TouchVG库库(https://github.com/rhcad/TouchVG

3.1 下载源码并编译

git clone https://github.com/rhcad/TouchVG.git

执行cd core && make

3.2sample程序

待补充

  1. Emscripten编译环境(https://emscripten.org/index.html)

4.1 下载编译

*# Get the emsdk repo*

git clone https:**//**github**.**com**/**emscripten**-**core**/**emsdk**.**git

cd emsdk

./emsdk install latest

./emsdk activate latest

source ./emsdk_env.sh
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,000评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,825评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,055评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,766评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,639评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,453评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,860评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,492评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,783评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,817评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,624评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,439评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,872评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,075评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,372评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,868评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,075评论 2 338

推荐阅读更多精彩内容