Windows编译skia
Win10(VS2019/2017,python2.7,翻墙):
- depot_tools:
- 下载至任意位置并添加至环境变量PATH:git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ninja:
- 下载至任意位置并添加至环境变量PATH:git clone git://github.com/ninja-build/ninja.git
- 进入ninja文件夹,执行python configure.py --bootstrap (确保python执行python2.7)
- 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
- 用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解决方案目录,但是有可能无法正确生成,尽量不要使用这个
- 用ninja工具生成可执行或库:
- ninja -C out/Static
- ninja -C out/Release
- ninja -C out/Debug
- 在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={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
image3. 添加扩展模块
我们根据samle程序里面提供的HelloWorld修改一个我们自己的HelloWorld程序
- 打开根目录下BUILD.gn找到test_app("HelloWorld"),拷贝复制HelloWorld程序
- 在example目录下copy HelloWorld.h HelloWorld.cpp到HelloWorld.h HelloWorld.cpp
- 重新执行bin/gn gen out/Debug生成编译配置
- 执行ninja -C out/Debug HelloWorld 指定编译HelloWorld模块, 生成并运行./out/Debug/HelloWorld
-
可以根据自己的需求封装自己的工程模块或修改skia提供的modules
-
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;
}
-
TouchVG库库(https://github.com/rhcad/TouchVG)
3.1 下载源码并编译
git clone https://github.com/rhcad/TouchVG.git
执行cd core && make
3.2sample程序
待补充
-
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