用skia实现2D绘制

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);
    }
}

效果如图
在这里插入图片描述

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Skia是一个开源的2D图形库,可以用于创建高质量的用户界面和图形应用程序。Skia支持多种平台,包括Linux。在Linux中使用Skia实现鼠标功能可以通过以下步骤实现: 1. 安装Skia库。Skia可以通过源代码下载和编译,也可以通过包管理器安装。在Ubuntu上,可以使用以下命令安装Skia: ``` sudo apt-get install libskia-dev ``` 2. 创建Skia应用程序。可以使用C++编写Skia应用程序,并使用Skia库中的函数绘制图形和处理输入事件。下面是一个示例程序,可以创建一个窗口并在窗口中绘制一个圆形: ``` #include <SkCanvas.h> #include <SkSurface.h> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> void display() { SkImageInfo info = SkImageInfo::MakeN32Premul(512, 512); SkSurface* surface = SkSurface::MakeRaster(info); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); SkPaint paint; paint.setColor(SK_ColorBLUE); canvas->drawCircle(256, 256, 128, paint); glDrawPixels(512, 512, GL_RGBA, GL_UNSIGNED_BYTE, surface->getCanvas()->getDevice()->accessPixels()); glutSwapBuffers(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(512, 512); glutCreateWindow("Skia Demo"); glutDisplayFunc(display); glutMainLoop(); return 0; } ``` 上面的程序使用Skia库创建一个512x512的窗口,并在窗口中绘制一个蓝色的圆形。程序使用OpenGL将绘制的图像显示在窗口中。 3. 实现鼠标功能。Skia库提供了处理输入事件的函数,可以使用这些函数来实现鼠标功能。例如,下面的代码可以在鼠标单击时输出鼠标位置: ``` void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { printf("Mouse clicked at (%d, %d)\n", x, y); } } int main(int argc, char** argv) { // ... glutMouseFunc(mouse); // ... } ``` 上面的代码将鼠标单击事件绑定到`mouse`函数,当鼠标左键按下时,将输出鼠标位置。 通过以上步骤,就可以在Linux中使用Skia实现鼠标功能。需要注意的是,Skia是一个2D图形库,并不包括窗口管理和输入事件处理等功能,需要结合其他库一起使用。在Linux中,可以使用OpenGL和GLUT库来创建窗口和处理输入事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值