skia是谷歌的一个开源2D引擎,用来实现利用CPU实现2D图形绘制。
下面是老朽写的一个例程,实现功能如下:
1.窗口的创建
2.图片解码
3.在窗口的任意位置绘制指定大小和透明度的图片
4.绘制文字
因为对OpenGL熟悉,所以不怎么喜欢用SDL,而是采用OpenGL创建绘制窗口。先由glfw创建窗口,然后skia负责渲染,最后opengl只负责将skia传过来的pixel画出来。
main函数如下
//
// Created by czh on 18-10-31.
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "window.h"
#include "dconfig.h"
Window blizzard(SCREEN_WIDTH, SCREEN_HEIGHT);
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 0 && key < 1024) {
if (action == GLFW_PRESS)
blizzard.keys[key] = GL_TRUE;
else if (action == GLFW_RELEASE)
blizzard.keys[key] = GL_FALSE;
}
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Blizzard", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, keyCallback);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
blizzard.init();
while (!glfwWindowShouldClose(window)) {
clock_t start = clock();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
blizzard.processInput();
blizzard.update();
blizzard.render(window);
glfwSwapBuffers(window);
glfwPollEvents();
#define FPS 1000/33
clock_t end = clock();
int time_ms = (double) (end - start) / CLOCKS_PER_SEC * 1000;
printf("#Render time: %d\n", time_ms);
if ((FPS - time_ms) > 0) {
usleep((FPS - time_ms) * 1000);
}
}
glfwTerminate();
return 0;
}
下面是头文件window.h
//
// Created by czh on 18-10-31.
//
#ifndef OPENGL_PRO_WINDOW_H
#define OPENGL_PRO_WINDOW_H
#include <game.h>
#include "calib/zhu.h"
#include <calib/checkerborad.h>
#include <calib/colormap.h>
#include <calib/zhang.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkPicture.h>
#include <SkTypeface.h>
#include <SkStream.h>
#include <SkCodec.h>
#include <SkAndroidCodec.h>
#include <SkImage.h>
class Window : public Game {
public:
SpriteRenderer *spriteRender;
sk_sp<SkTypeface> font;
SkBitmap bmMaster;
sk_sp<SkImage> image;
SkCanvas *canvas;
sk_sp<SkImage> imageServant;
SkBitmap bmServant;
cv::VideoCapture capture;
Window(GLuint width, GLuint height);
void init();
void destory();
void processInput();
void update();
void render(GLFWwindow *window);
SkBitmap loadTexture2DToSkBitmap( std::string file);
sk_sp<SkImage> loadTexture2DToSkImage(std::string file);
void draw(SkCanvas *canvas, sk_sp<SkImage> image, int posX, int posY, int sizeX, int sizeY, uchar alpha = 0xff);
void draw(SkCanvas *canvas, SkBitmap bitmap, int posX, int posY, int sizeX, int sizeY, uchar alpha = 0xff);
void drawFront(SkCanvas *canvas, std::string text, int posX, int posY, float size, uint color, uchar alpha = 0xff);
};
#endif //OPENGL_PRO_WINDOW_H
最后是window.cpp
//
// Created by czh on 18-10-31.
//
#include "window.h"
Window::Window(GLuint width, GLuint height) : Game(width, height) {
canvas = nullptr;
}
void Window::init() {
StatusManager::renderMode = Render_2D;
StatusManager::init();
this->state = GAME_ACTIVE;
ResourceManager::loadShader("sprite", ResourceManager::defaultVshader2D, ResourceManager::defaultFshader2D);
spriteRender = new SpriteRenderer();
spriteRender->init(ResourceManager::getShader("sprite"));
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::ortho(0.0f, static_cast<GLfloat>(this->width), static_cast<GLfloat>(this->height), 0.0f,
-1.0f, 1.0f);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));//move
model = glm::rotate(model, glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));//rotate
model = glm::scale(model, glm::vec3(SCREEN_WIDTH, SCREEN_HEIGHT, 1.0f)); //scale
ResourceManager::getShader("sprite").setMatrix4("projection", projection);
ResourceManager::getShader("sprite").setMatrix4("model", model);
ResourceManager::getShader("sprite").setVector3f("spriteColor", glm::vec3(1.0, 1.0, 1.0));
bmMaster.allocPixels(SkImageInfo::Make(1920, 720, kN32_SkColorType, kPremul_SkAlphaType));
bmMaster.eraseColor(0xFF000000);
canvas = new SkCanvas(bmMaster);
//imageServant = loadTexture2DToSkImage("../res/colorMap.png");
bmServant = loadTexture2DToSkBitmap("../res/colorMap.png");
}
void Window::destory() {
Game::destroy();
}
void Window::processInput() {
}
SkBitmap Window::loadTexture2DToSkBitmap(std::string file) {
clock_t start = clock();
SkBitmap bitmap;
SkString path(file.c_str());
sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
if (!data) {
printf("Missing file %s", path.c_str());
}
auto codec = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromData(std::move(data)));
SkImageInfo info = codec->getInfo();
bitmap.allocPixels(SkImageInfo::Make(info.width(), info.height(), kN32_SkColorType, kPremul_SkAlphaType));
SkCodec::Result result = codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes());
if (result == SkCodec::kSuccess) {
printf("#Codec success\n");
} else {
printf("#Codec failure\n");
}
clock_t end = clock();
int time_ms = (double) (end - start) / CLOCKS_PER_SEC * 1000;
printf("#loadTexture2DToSkBitmap time: %d\n", time_ms);
return bitmap;
}
sk_sp<SkImage> Window::loadTexture2DToSkImage(std::string file) {
clock_t start = clock();
sk_sp<SkData> data = SkData::MakeFromFileName(file.c_str());
sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
clock_t end = clock();
int time_ms = (double) (end - start) / CLOCKS_PER_SEC * 1000;
printf("#loadTexture2DToSkImage time: %d\n", time_ms);
return image;
}
void Window::draw(SkCanvas *canvas, sk_sp<SkImage> image, int posX, int posY, int sizeX, int sizeY, uchar alpha) {
SkRect rect;
rect.setXYWH(posX, posY, posX + sizeX, posY + sizeY);
SkPaint paint;
paint.setAlpha(alpha);
canvas->drawImageRect(image, rect, &paint);
}
void Window::draw(SkCanvas *canvas, SkBitmap bitmap, int posX, int posY, int sizeX, int sizeY, uchar alpha) {
SkRect rect;
rect.setXYWH(posX, posY, posX + sizeX, posY + sizeY);
SkPaint paint;
paint.setAlpha(alpha);
canvas->drawBitmapRect(bitmap, rect, &paint);
}
void Window::drawFront(SkCanvas *canvas, std::string text, int posX, int posY, float size, uint color, uchar alpha) {
SkPaint paint;
paint.setARGB(uchar(color >> 24), uchar(color >> 16), uchar(color >> 8), (uchar)color);
paint.setTypeface(SkTypeface::MakeFromFile("../res/fangsong.ttf"));
paint.setTextSize(size);
paint.setAlpha(alpha);
std::string title(text.c_str());
canvas->drawText(title.c_str(), title.length(), posX, posY, paint);
}
void Window::update() {
canvas->clear(0x00000000);
static int i = 0;
//1.0 decode with bitmap
draw(canvas, bmServant, 0, 0, 1920, 720, 0xff);
drawFront(canvas, "abcd12341234哈哈哈", 100, 50, 25, 0xffff0000, 0xff);
ResourceManager::loadTexture2D("codec_data", (uchar *) bmMaster.getPixels(), bmMaster.width(), bmMaster.height(), 4);
//2.0 decode with image
//draw(canvas, imageServant, 0, 0, 1920, 720, 0xff);
//drawFront(canvas, "123456789", 100, 50, 25, 0xffff0000, 0xff);
//ResourceManager::loadTexture2D("codec_data", (uchar *) bmMaster.getPixels(), bmMaster.width(), bmMaster.height(), 4);
}
void Window::render(GLFWwindow *window) {
if (this->state == GAME_ACTIVE) {
spriteRender->drawSprite(ResourceManager::getTexture2D("codec_data"));
usleep(1000 * 30);
}
}
效果如图