Skip to content

Instantly share code, notes, and snippets.

@stevenlstarr
Last active April 20, 2024 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenlstarr/4721858b1cc4da0f579feac6a4c2e4fb to your computer and use it in GitHub Desktop.
Save stevenlstarr/4721858b1cc4da0f579feac6a4c2e4fb to your computer and use it in GitHub Desktop.
SFML 2.6, Skia 0.34.0, Yoga Layout 3.0 Example
#define SK_GL
// Compile command:
// This project uses the Skia graphics library along with SFML, EGL, and other libraries.
// Compilation requires linking against these libraries as specified below.
// g++ -o test test.cpp -I/usr/include/skia -lskia -lsfml-graphics -lsfml-window -lsfml-system -lyogacore -lEGL -lGLESv2
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <SFML/Graphics.hpp>
#include <memory>
#include <yoga/Yoga.h>
#include <cmath> // Include for mathematical functions like sin and cos
#include <iostream>
#include <skia/include/gpu/GrDirectContext.h>
#include <skia/include/gpu/gl/GrGLInterface.h>
#include <skia/include/core/SkSurface.h>
#include <skia/include/core/SkCanvas.h>
#include <skia/include/core/SkPath.h>
#include <skia/include/core/SkPaint.h>
#include <skia/include/core/SkRect.h>
#include <skia/include/core/SkRRect.h>
// Function to create and return an SkRRect representing a rounded rectangle
SkRRect createRoundedRectangle(float x, float y, float width, float height,
float radiusTopLeft, float radiusTopRight,
float radiusBottomRight, float radiusBottomLeft) {
// Define the rectangle from specified position and size
SkRect rect = SkRect::MakeXYWH(x, y, width, height);
// Define radii for each corner of the rectangle
SkVector radii[4];
radii[SkRRect::kUpperLeft_Corner] = SkVector::Make(radiusTopLeft, radiusTopLeft);
radii[SkRRect::kUpperRight_Corner] = SkVector::Make(radiusTopRight, radiusTopRight);
radii[SkRRect::kLowerRight_Corner] = SkVector::Make(radiusBottomRight, radiusBottomRight);
radii[SkRRect::kLowerLeft_Corner] = SkVector::Make(radiusBottomLeft, radiusBottomLeft);
// Create and return the rounded rectangle with individual corner radii
SkRRect roundedRect;
roundedRect.setRectRadii(rect, radii);
return roundedRect;
}
int main() {
// Initialize an SFML window
sf::RenderWindow window(sf::VideoMode(800, 600), "Hydra v0.0.1");
// Setup Skia OpenGL context
sk_sp<const GrGLInterface> interface = GrGLMakeNativeInterface();
sk_sp<GrDirectContext> context = GrDirectContext::MakeGL(interface);
// Define the image properties and create a Skia GPU surface
SkImageInfo imageinfo = SkImageInfo::MakeN32Premul(800, 600);
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context.get(), SkBudgeted::kNo, imageinfo);
// Ensure the GPU surface was created successfully
if (!surface) {
std::cerr << "Failed to create Skia GPU surface\n";
return -1;
}
// Prepare the Skia drawing context
context->flush();
// Retrieve the canvas from the Skia surface
SkCanvas* canvas = surface->getCanvas();
// Activate SFML window context
window.setActive(true);
// Set up Yoga layout for UI elements
YGNodeRef container = YGNodeNew();
YGNodeStyleSetWidth(container, 800);
YGNodeStyleSetHeight(container, 100);
YGNodeStyleSetFlexDirection(container, YGFlexDirectionRow);
YGNodeStyleSetPadding(container, YGEdgeAll, 20);
// Create and configure child nodes for layout
YGNodeRef child = YGNodeNew();
YGNodeStyleSetFlexGrow(child, 1); // Allow the child to grow and fill the container
YGNodeStyleSetMargin(child, YGEdgeAll, 5);
YGNodeInsertChild(container, child, 0);
YGNodeRef child1 = YGNodeNew();
YGNodeStyleSetFlexGrow(child1, 1);
YGNodeStyleSetMargin(child1, YGEdgeAll, 5);
YGNodeInsertChild(container, child1, 1);
// Compute the layout for all children
YGNodeCalculateLayout(container, YGUndefined, YGUndefined, YGDirectionLTR);
// Main application loop
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
// Handle window resizing
if (event.type == sf::Event::Resized) {
sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
window.setView(sf::View(visibleArea));
}
}
// Clear window with a specific color
window.clear(sf::Color(23, 23, 23));
// Start drawing operations
canvas->clear(SkColorSetARGB(255, 255, 255, 0)); // Clear with yellow color, full opacity
// Draw rounded and regular rectangles based on Yoga layout
SkRRect rect = createRoundedRectangle(YGNodeLayoutGetLeft(child), YGNodeLayoutGetTop(child), YGNodeLayoutGetWidth(child), YGNodeLayoutGetHeight(child), 0, 20, 0, 20);
SkPaint paint;
paint.setAntiAlias(true); // Enable anti-aliasing for smoother edges
paint.setColor(SK_ColorBLUE);
canvas->drawRRect(rect, paint);
SkRect rect1 = SkRect::MakeXYWH(YGNodeLayoutGetLeft(child1), YGNodeLayoutGetTop(child1), YGNodeLayoutGetWidth(child1), YGNodeLayoutGetHeight(child1));
SkPaint paint1;
paint1.setAntiAlias(true);
paint1.setColor(SK_ColorRED);
canvas->drawRect(rect1, paint1);
// Finish drawing and update the canvas
canvas->flush();
// Display the updated window
window.display();
}
// Cleanup
delete canvas;
return 0;
}
@stevenlstarr
Copy link
Author

This example uses SFML for Window, Input and GL Context, Skia for Canvas and 2D Graphics on a GPU Surface and Yoga Layout Engine for Flexbox layout.

https://github.com/SFML/SFML
https://github.com/SFML/SFML/archive/refs/tags/2.6.1.zip

https://github.com/google/skia
https://github.com/google/skia/archive/refs/tags/canvaskit/0.34.0.zip

https://github.com/facebook/yoga
https://github.com/facebook/yoga/archive/refs/tags/v3.0.4.zip

 g++ -o test test.cpp -I/usr/include/skia -lskia -lsfml-graphics -lsfml-window -lsfml-system -lthorvg -lyogacore -lEGL -lGLESv2 

Example Code

#define SK_GL

// Compile command:
// This project uses the Skia graphics library along with SFML, EGL, and other libraries. 
// Compilation requires linking against these libraries as specified below.
// g++ -o test test.cpp -I/usr/include/skia -lskia -lsfml-graphics -lsfml-window -lsfml-system  -lyogacore -lEGL -lGLESv2 

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

#include <SFML/Graphics.hpp>
#include <memory>
#include <yoga/Yoga.h>
#include <cmath>  // Include for mathematical functions like sin and cos
#include <iostream>

#include <skia/include/gpu/GrDirectContext.h>
#include <skia/include/gpu/gl/GrGLInterface.h>
#include <skia/include/core/SkSurface.h>
#include <skia/include/core/SkCanvas.h>
#include <skia/include/core/SkPath.h>
#include <skia/include/core/SkPaint.h>
#include <skia/include/core/SkRect.h>
#include <skia/include/core/SkRRect.h>

// Function to create and return an SkRRect representing a rounded rectangle
SkRRect createRoundedRectangle(float x, float y, float width, float height,
                               float radiusTopLeft, float radiusTopRight,
                               float radiusBottomRight, float radiusBottomLeft) {
    // Define the rectangle from specified position and size
    SkRect rect = SkRect::MakeXYWH(x, y, width, height);

    // Define radii for each corner of the rectangle
    SkVector radii[4];
    radii[SkRRect::kUpperLeft_Corner] = SkVector::Make(radiusTopLeft, radiusTopLeft);
    radii[SkRRect::kUpperRight_Corner] = SkVector::Make(radiusTopRight, radiusTopRight);
    radii[SkRRect::kLowerRight_Corner] = SkVector::Make(radiusBottomRight, radiusBottomRight);
    radii[SkRRect::kLowerLeft_Corner] = SkVector::Make(radiusBottomLeft, radiusBottomLeft);

    // Create and return the rounded rectangle with individual corner radii
    SkRRect roundedRect;
    roundedRect.setRectRadii(rect, radii);

    return roundedRect;
}

int main() {
    // Initialize an SFML window
    sf::RenderWindow window(sf::VideoMode(800, 600), "Hydra v0.0.1");

    // Setup Skia OpenGL context
    sk_sp<const GrGLInterface> interface = GrGLMakeNativeInterface();
    sk_sp<GrDirectContext> context = GrDirectContext::MakeGL(interface);

    // Define the image properties and create a Skia GPU surface
    SkImageInfo imageinfo = SkImageInfo::MakeN32Premul(800, 600);
    sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context.get(), SkBudgeted::kNo, imageinfo);

    // Ensure the GPU surface was created successfully
    if (!surface) {
        std::cerr << "Failed to create Skia GPU surface\n";
        return -1;
    }

    // Prepare the Skia drawing context
    context->flush();

    // Retrieve the canvas from the Skia surface
    SkCanvas* canvas = surface->getCanvas();

    // Activate SFML window context
    window.setActive(true);

    // Set up Yoga layout for UI elements
    YGNodeRef container = YGNodeNew();
    YGNodeStyleSetWidth(container, 800);
    YGNodeStyleSetHeight(container, 100);
    YGNodeStyleSetFlexDirection(container, YGFlexDirectionRow);
    YGNodeStyleSetPadding(container, YGEdgeAll, 20);

    // Create and configure child nodes for layout
    YGNodeRef child = YGNodeNew();
    YGNodeStyleSetFlexGrow(child, 1);  // Allow the child to grow and fill the container
    YGNodeStyleSetMargin(child, YGEdgeAll, 5);
    YGNodeInsertChild(container, child, 0);

    YGNodeRef child1 = YGNodeNew();
    YGNodeStyleSetFlexGrow(child1, 1);
    YGNodeStyleSetMargin(child1, YGEdgeAll, 5);
    YGNodeInsertChild(container, child1, 1);

    // Compute the layout for all children
    YGNodeCalculateLayout(container, YGUndefined, YGUndefined, YGDirectionLTR);

    // Main application loop
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            // Handle window resizing
            if (event.type == sf::Event::Resized) {
                sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
                window.setView(sf::View(visibleArea));
            }
        }

        // Clear window with a specific color
        window.clear(sf::Color(23, 23, 23));

        // Start drawing operations
        canvas->clear(SkColorSetARGB(255, 255, 255, 0));  // Clear with yellow color, full opacity

        // Draw rounded and regular rectangles based on Yoga layout
        SkRRect rect = createRoundedRectangle(YGNodeLayoutGetLeft(child), YGNodeLayoutGetTop(child), YGNodeLayoutGetWidth(child), YGNodeLayoutGetHeight(child), 0, 20, 0, 20);
        SkPaint paint;
        paint.setAntiAlias(true);  // Enable anti-aliasing for smoother edges
        paint.setColor(SK_ColorBLUE);
        canvas->drawRRect(rect, paint);

        SkRect rect1 = SkRect::MakeXYWH(YGNodeLayoutGetLeft(child1), YGNodeLayoutGetTop(child1), YGNodeLayoutGetWidth(child1), YGNodeLayoutGetHeight(child1));
        SkPaint paint1;
        paint1.setAntiAlias(true);
        paint1.setColor(SK_ColorRED);
        canvas->drawRect(rect1, paint1);
        
        // Finish drawing and update the canvas
        canvas->flush();

        // Display the updated window
        window.display();
    }

    // Cleanup
    delete canvas;

    return 0;
}

Screenshot

Screenshot from 2024-04-20 14-03-18

Shell Script to build skia

#!/bin/bash

# Set the PKG directory where everything will be installed
export PKG=$(pwd)/install

# Ensure the PKG directory exists
mkdir -pv $PKG

git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'
export PATH="${PWD}/depot_tools:${PATH}"

# Download the packages
wget https://github.com/google/skia/archive/refs/tags/canvaskit/0.34.0.tar.gz

tar -xvf 0.34.0.tar.gz

# Change directory to the glibc directory
cd skia-canvaskit-0.34.0

python3 tools/git-sync-deps

# Run configure with the adjusted paths
./bin/gn gen 'out/Shared' --args='
    is_official_build=true 
    is_component_build=true
    skia_enable_tools=false
    target_os="linux" 
    target_cpu="x64"
    skia_use_icu=false 
    skia_use_sfntly=false 
    skia_use_piex=true
    skia_use_system_expat=false 
    skia_use_system_freetype2=false 
    skia_use_system_libjpeg_turbo=false 
    skia_use_system_libpng=false 
    skia_use_system_libwebp=false 
    skia_use_system_zlib=false
    skia_enable_gpu=true'

ninja -C out/Shared

cd $PKG
mkdir -p usr/lib64
mkdir -p usr/include/skia

cd $PKG/usr/lib64
cp ../../../skia-canvaskit-0.34.0/out/Shared/*.a .
cp ../../../skia-canvaskit-0.34.0/out/Shared/*.so .

cd $PKG/usr/include/skia
cp -r ../../../../skia-canvaskit-0.34.0/include/* .

cd $PKG
#zip -r9 ../skia-0.34.0-1.pkg usr/lib64/
#zip -r9 ../skia-devel-0.34.0-1.pkg usr/include/

# Cleanup
#cd ..
#rm -rf 0.34.0.tar.gz install skia-canvaskit-0.34.0 depot_tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment