Skip to content

Commit 43b1a4d

Browse files
committed
Simpler versions of Another-SkiaSDLExample
1 parent eb192ea commit 43b1a4d

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed

Another-SkiaSDLExample_v2.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright 2025, Hin-Tak Leung
5+
6+
# SDL3 Re-write / simplication
7+
8+
# See https://github.com/HinTak/skia-python-examples/issues/6
9+
10+
from sdl3 import \
11+
SDLK_ESCAPE, SDL_CreateWindow, SDL_DestroyWindow, \
12+
SDL_EVENT_QUIT, \
13+
SDL_Event, SDL_GL_CONTEXT_MAJOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION, \
14+
SDL_GL_CONTEXT_PROFILE_CORE, SDL_GL_CONTEXT_PROFILE_MASK, \
15+
SDL_GL_CreateContext, SDL_GL_DEPTH_SIZE, SDL_GL_DOUBLEBUFFER, \
16+
SDL_GL_DestroyContext, \
17+
SDL_GL_GetAttribute, SDL_GL_MakeCurrent, SDL_GL_STENCIL_SIZE, \
18+
SDL_GL_SetAttribute, SDL_GL_SetSwapInterval, SDL_GL_SwapWindow, \
19+
SDL_GetError, SDL_GetWindowSizeInPixels, \
20+
SDL_INIT_VIDEO, SDL_Init, SDL_PollEvent, SDL_Quit, \
21+
SDL_WINDOW_OPENGL
22+
23+
import skia
24+
from OpenGL import GL
25+
import ctypes
26+
27+
width, height = 640, 480
28+
title = b"Skia + PySDL3 Example"
29+
30+
def main():
31+
if not SDL_Init(SDL_INIT_VIDEO):
32+
raise RuntimeError(f"SDL_Init Error: {SDL_GetError()}")
33+
34+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)
35+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3)
36+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)
37+
38+
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)
39+
40+
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0)
41+
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8)
42+
43+
window = SDL_CreateWindow(
44+
title,
45+
width, height,
46+
SDL_WINDOW_OPENGL
47+
)
48+
if not window:
49+
raise RuntimeError(f"SDL_CreateWindow Error: {SDL_GetError()}")
50+
51+
gl_context = SDL_GL_CreateContext(window)
52+
if not gl_context:
53+
SDL_DestroyWindow(window)
54+
raise RuntimeError(f"SDL_GL_CreateContext Error: {SDL_GetError()}")
55+
56+
if not SDL_GL_MakeCurrent(window, gl_context):
57+
SDL_GL_DestroyContext(gl_context)
58+
SDL_DestroyWindow(window)
59+
raise RuntimeError(f"SDL_GL_MakeCurrent Error: {SDL_GetError()}")
60+
61+
context = skia.GrDirectContext.MakeGL()
62+
if not context:
63+
raise RuntimeError("Failed to create Skia GrDirectContext")
64+
65+
fb_width, fb_height = ctypes.c_int(), ctypes.c_int()
66+
SDL_GetWindowSizeInPixels(window, ctypes.byref(fb_width), ctypes.byref(fb_height))
67+
68+
# Check how many stencil bits we actually got
69+
stencil_bits = ctypes.c_int()
70+
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, ctypes.byref(stencil_bits))
71+
assert stencil_bits.value == 8
72+
73+
backend_render_target = skia.GrBackendRenderTarget(
74+
fb_width.value,
75+
fb_height.value,
76+
0, # sampleCnt (MSAA samples) | samples - usually 0 for direct to screen
77+
stencil_bits.value, # stencilBits - Use value retrieved from GL context
78+
# Framebuffer ID 0 means the default window framebuffer
79+
skia.GrGLFramebufferInfo(0, GL.GL_RGBA8) # Target format GL_RGBA8 | Use 0 for framebuffer object ID for default framebuffer
80+
)
81+
82+
surface = skia.Surface.MakeFromBackendRenderTarget(
83+
context, backend_render_target, skia.kBottomLeft_GrSurfaceOrigin,
84+
skia.kRGBA_8888_ColorType, skia.ColorSpace.MakeSRGB())
85+
86+
if surface is None:
87+
context.abandonContext()
88+
raise RuntimeError("Failed to create Skia Surface from BackendRenderTarget")
89+
90+
running = True
91+
event = SDL_Event() # Create event structure once
92+
93+
while running:
94+
while SDL_PollEvent(event):
95+
if event.type == SDL_EVENT_QUIT:
96+
print("Quit event received.")
97+
running = False
98+
break
99+
100+
if not running:
101+
break
102+
103+
GL.glClearColor(0.0, 0.0, 0.0, 1.0) # Black background
104+
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT)
105+
106+
with surface as canvas:
107+
# Example drawing: Clear with Skia color, draw circle
108+
canvas.clear(skia.ColorWHITE)
109+
paint = skia.Paint(
110+
Color=skia.ColorBLUE,
111+
StrokeWidth=2,
112+
Style=skia.Paint.kStroke_Style, # Make it an outline
113+
AntiAlias=True
114+
)
115+
canvas.drawCircle(width / 2, height / 2, 100, paint)
116+
117+
paint.setColor(skia.ColorGREEN)
118+
paint.setStyle(skia.Paint.kFill_Style) # Fill style
119+
canvas.drawRect(skia.Rect.MakeXYWH(20, 20, 80, 80), paint)
120+
121+
surface.flushAndSubmit()
122+
123+
SDL_GL_SwapWindow(window)
124+
125+
context.abandonContext()
126+
127+
if gl_context:
128+
SDL_GL_DestroyContext(gl_context)
129+
if window:
130+
SDL_DestroyWindow(window)
131+
132+
SDL_Quit()
133+
134+
if __name__ == '__main__':
135+
main()

Another-SkiaSDLExample_v2_sdl2.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright 2025, Hin-Tak Leung
5+
6+
# SDL2 Re-write / simplication
7+
8+
# See https://github.com/HinTak/skia-python-examples/issues/6
9+
10+
from sdl2 import \
11+
SDLK_ESCAPE, SDL_CreateWindow, SDL_DestroyWindow, \
12+
SDL_QUIT, \
13+
SDL_Event, SDL_GL_CONTEXT_MAJOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION, \
14+
SDL_GL_CONTEXT_PROFILE_CORE, SDL_GL_CONTEXT_PROFILE_MASK, \
15+
SDL_GL_CreateContext, SDL_GL_DEPTH_SIZE, SDL_GL_DOUBLEBUFFER, \
16+
SDL_GL_DeleteContext, \
17+
SDL_GL_GetAttribute, SDL_GL_MakeCurrent, SDL_GL_STENCIL_SIZE, \
18+
SDL_GL_SetAttribute, SDL_GL_SetSwapInterval, SDL_GL_SwapWindow, \
19+
SDL_GetError, SDL_GetWindowSizeInPixels, \
20+
SDL_INIT_VIDEO, SDL_Init, SDL_PollEvent, SDL_Quit, \
21+
SDL_WINDOWPOS_CENTERED, \
22+
SDL_WINDOW_OPENGL
23+
24+
import skia
25+
from OpenGL import GL
26+
import ctypes
27+
28+
width, height = 640, 480
29+
title = b"Skia + PySDL2 Example"
30+
31+
def main():
32+
if SDL_Init(SDL_INIT_VIDEO) != 0:
33+
raise RuntimeError(f"SDL_Init Error: {SDL_GetError()}")
34+
35+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)
36+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3)
37+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)
38+
39+
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)
40+
41+
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0)
42+
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8)
43+
44+
window = SDL_CreateWindow(
45+
title,
46+
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
47+
width, height,
48+
SDL_WINDOW_OPENGL
49+
)
50+
if not window:
51+
raise RuntimeError(f"SDL_CreateWindow Error: {SDL_GetError()}")
52+
53+
gl_context = SDL_GL_CreateContext(window)
54+
if not gl_context:
55+
SDL_DestroyWindow(window)
56+
raise RuntimeError(f"SDL_GL_CreateContext Error: {SDL_GetError()}")
57+
58+
if SDL_GL_MakeCurrent(window, gl_context) !=0:
59+
SDL_GL_DeleteContext(gl_context)
60+
SDL_DestroyWindow(window)
61+
raise RuntimeError(f"SDL_GL_MakeCurrent Error: {SDL_GetError()}")
62+
63+
context = skia.GrDirectContext.MakeGL()
64+
if not context:
65+
raise RuntimeError("Failed to create Skia GrDirectContext")
66+
67+
fb_width, fb_height = ctypes.c_int(), ctypes.c_int()
68+
SDL_GetWindowSizeInPixels(window, ctypes.byref(fb_width), ctypes.byref(fb_height))
69+
70+
# Check how many stencil bits we actually got
71+
stencil_bits = ctypes.c_int()
72+
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, ctypes.byref(stencil_bits))
73+
assert stencil_bits.value == 8
74+
75+
backend_render_target = skia.GrBackendRenderTarget(
76+
fb_width.value,
77+
fb_height.value,
78+
0, # sampleCnt (MSAA samples) | samples - usually 0 for direct to screen
79+
stencil_bits.value, # stencilBits - Use value retrieved from GL context
80+
# Framebuffer ID 0 means the default window framebuffer
81+
skia.GrGLFramebufferInfo(0, GL.GL_RGBA8) # Target format GL_RGBA8 | Use 0 for framebuffer object ID for default framebuffer
82+
)
83+
84+
surface = skia.Surface.MakeFromBackendRenderTarget(
85+
context, backend_render_target, skia.kBottomLeft_GrSurfaceOrigin,
86+
skia.kRGBA_8888_ColorType, skia.ColorSpace.MakeSRGB())
87+
88+
if surface is None:
89+
context.abandonContext()
90+
raise RuntimeError("Failed to create Skia Surface from BackendRenderTarget")
91+
92+
running = True
93+
event = SDL_Event() # Create event structure once
94+
95+
while running:
96+
while SDL_PollEvent(event):
97+
if event.type == SDL_QUIT:
98+
print("Quit event received.")
99+
running = False
100+
break
101+
102+
if not running:
103+
break
104+
105+
GL.glClearColor(0.0, 0.0, 0.0, 1.0) # Black background
106+
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT)
107+
108+
with surface as canvas:
109+
# Example drawing: Clear with Skia color, draw circle
110+
canvas.clear(skia.ColorWHITE)
111+
paint = skia.Paint(
112+
Color=skia.ColorBLUE,
113+
StrokeWidth=2,
114+
Style=skia.Paint.kStroke_Style, # Make it an outline
115+
AntiAlias=True
116+
)
117+
canvas.drawCircle(width / 2, height / 2, 100, paint)
118+
119+
paint.setColor(skia.ColorGREEN)
120+
paint.setStyle(skia.Paint.kFill_Style) # Fill style
121+
canvas.drawRect(skia.Rect.MakeXYWH(20, 20, 80, 80), paint)
122+
123+
surface.flushAndSubmit()
124+
125+
SDL_GL_SwapWindow(window)
126+
127+
context.abandonContext()
128+
129+
if gl_context:
130+
SDL_GL_DeleteContext(gl_context)
131+
if window:
132+
SDL_DestroyWindow(window)
133+
134+
SDL_Quit()
135+
136+
if __name__ == '__main__':
137+
main()

0 commit comments

Comments
 (0)