Evet, sevgili yazılımperver dostlarım, hatırlarsanız, bir süredir daha basit projeler ile SDL3, CI/CD ve benzeri konulara bakıyor ve cpp-playground reposu üzerinden bunları deniyorduk. Açıkçası o çalışmaları güzel bir noktaya getirdik. Şimdi orada gördüğümüz kavram ve araçları bir sonraki noktaya taşıma vakti geldi. Uzun süredir, hazırlıklarını yaptığım kütüphane, nihayet belirli bir olgunluğa erişti ve artık yeni bir sayfaya geçiyoruz.
İçerik
SDLPainter nedir?
QPainter sınıfından ilham alan, SDL3 ve OpenGL 3.3 (ve dahi Vulkan) üzerine inşa edilmiş, modern C++ kullanan bir 2B çizim kütüphanesidir.begin(), end(), setPen(), setBrush() gibi birkaç satırla ekrana 2B şekiller çizebiliyorsunuz. Bu API’lerin arkasındaki işlevleri Qt hallediyor.
Tasarımsal Konular
IRenderer adında soyut bir arayüz ekledim. Genel kullanım mimarisi aşağıdaki gibi:Tessellator sınıfı temelde şekilleri vertex’lere dönüştürüyor ve backend’den tamamen bağımsız. Hem OpenGL hem de Vulkan ile kullanılabilecek. Aşağıda mimarinin daha detaylı görünümünü bulabilirsiniz (detaylar için https://github.com/yazilimperver/sdl-painter/blob/main/doc/mimari-genel-bakis.md)
- glLineWidth kullanmıyorum: OpenGL’de
glLineWidthile kalın çizgi çizmek platformdan platforma değişebildiği için, bu API direk kullanılmıyor, tavsiye de edilmiyor. Bunun yerine geometri tabanlı quad çizim yaklaşımı kullanılıyor (çizginin yönüne dik normal hesaplayıp her iki yöne kalınlığın yarısı kadar genişletiliyor ve iki üçgenden oluşan bir quad olarak render ediliyor) ki bu kütüphanede de o yaklaşım izlendi. - Adaptif segment sayısı: Daire ve elips çizmek için OpenGL’de triangle fan kullanılıyor. Segment sayısı sabit değil, yarıçapa göre değişiyor:
-
1int segments = std::max(16, static_cast<int>(radius * 0.5f));
- Küçük daireler az segment, büyük daireler daha fazla — hem performans hem görsel kaliteyi koruma adına böyle bir yol izliyoruz.
-
- Ear Clipping triangulation: Konkav poligonlar için basit triangle fan kullanılamadığı için
Tessellatorsınıfı içinde ear clipping algoritması implement edildi. - GLM yok (şimdilik), kendi transform matrisimiz var. Transform stack için 3×3 affine matris kullanılıyor. uEngine’de glm kullanıyordum, buraya da ekleyeceğim ama acil değil.
- Resim/Doku yükleme kütüphanesi: Bir diğer konu doku/texture/imaj dosyalarının okunması için kullanılacak kütüphane. Açıkçası bu zamana kadar hep SDL_Image kullandım. Bu kütüphane için stb_image kütüphanesi kullanacağım.
Genel Özellikler
Çizim Primitifleri
- Çizgi (
DrawLine) - Dikdörtgen — stroke ve fill (
DrawRect/FillRect) - Daire — stroke ve fill (
DrawCircle/FillCircle) - Elips — stroke ve fill (
DrawEllipse/FillEllipse) - Çokgen — stroke ve fill (
DrawPolygon/FillPolygon) - Polyline (
DrawPolyline)
Görsel Stiller
- Pen: renk + kalınlık (geometry-based quad;
glLineWidthkullanılmıyor) - Brush: dolgu rengi
- Opacity: global saydamlık
[0.0, 1.0]
Transform Stack
Translate,Rotate,ScaleSave/Restore— QPainter ile birebir aynı semantikResetTransform- 3×3 affine matris
Clipping
- Scissor-based rect clip (
SetClipRect/ClearClip)
Image / Texture
- PNG ve JPG yükleme (stb_image)
- Tam kaynak rect → hedef rect ölçekleme
- Alpha blending desteği
Metin Çizimi
- SDL_ttf 3.x üzerinden font yükleme
- Glyph cache
- Alignment: left / center / right
- Rect içine metin yerleştirme

Tessellator
- Backend’den bağımsız vertex üretimi
- Daire/elips için adaptif segment sayısı:
max(16, int(radius * 0.5f)) - Konkav çokgenler için ear clipping triangulation
Render Batcher
Her çizim çağrısı doğrudan GPU’ya gönderilmiyor; RenderBatcher vertex’leri bir arabellekte biriktiriyor ve yalnızca mod, texture veya opacity değiştiğinde (ya da 8192 vertex limiti dolduğunda) Flush() ile toplu olarak renderer’a iletiyor. Bu yaklaşım, özellikle çok sayıda küçük şeklin ard arda çizildiği sahnelerde draw call sayısını ciddi ölçüde azaltıyor. İhtiyacımız olacak 😉
Backend Desteği
- OpenGL 3.3 Core — GLAD loader, GLSL shader’lar
- Vulkan 1.1 — SPIR-V pipeline (Phase 5, opsiyonel)
IRendererarayüzü — yeni backend eklemek için tek implementasyon noktası
Platform Desteği
- Linux (GCC / Clang, Ninja)
- Windows (MSVC, Visual Studio 2022)
- Linux container içinde Windows cross-compile (MinGW-w64), ayrıca windows için native container
Altyapı
- CMake Presets’ler Mevcut (7 preset:
linux-debug,linux-release,linux-debug-asan,windows-debug,windows-release,windows-mingw-debug,windows-mingw-release) - Conan 2 bağımlılık yönetimi — opsiyonel Vulkan bağımlılıkları
- Docker multi-stage: geliştirme / headless CI / cross-compile / native window
- CI/CD’yi hızlandırmak adına conan install adımları da bu imajlar içerisine eklendi
- Gitlab Container Registry kullanımı
- Github actions için ise Docker Hub kullanımı
- GitLab + Github CI/CD: build → test → quality (clang-format zorunlu, clang-tidy soft)
- AddressSanitizer + UBSan preset (
linux-debug-asan) - Google C++ Style, clang-format-18
API Nasıl Görünüyor?
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include "sdl_painter/painter.h" // Pencere ve painter'ı oluştur sdl_painter::Painter painter(window, sdl_painter::RendererBackend::kOpenGL); // Frame döngüsü painter.Begin(); painter.Clear({30, 30, 30, 255}); // Koyu gri arkaplan // Kırmızı kenarlık, yarı saydam mavi dolgu painter.SetPen(sdl_painter::Pen({255, 0, 0, 255}, 2.0f)); painter.SetBrush(sdl_painter::Brush({100, 100, 255, 128})); painter.DrawRect(50, 50, 200, 150); painter.DrawCircle(400, 300, 80); // Transform stack: kaydet, döndür, geri yükle painter.Save(); painter.Translate(400, 300); painter.Rotate(45.0f); painter.DrawRect(-50, -50, 100, 100); // 45° dönmüş dikdörtgen painter.Restore(); painter.End(); |
Yazı Planım
Gelelim bundan sonra, buna yönelik yazılarıma. Yazılarımı, kabiliyetlere göre bölmeye çalışacağım ve bir geliştirici günlüpü notları tadında olacak. Aslında mevcut örnekler de size bu konua fikir verebilir. İlk yazılarım muhtemelen şu başlıklardan oluşacak:
Sonuç
