Skip to content

Commit faebb57

Browse files
feat: image support added to drawing
1 parent 60d413c commit faebb57

22 files changed

Lines changed: 1254 additions & 303 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ shader-temp/
77
cache/
88

99
# python
10+
examples/__pycache__/
1011
scripts/__pycache__/
1112
sandbox/__pycache__/
1213
pilotlight/__pycache__/

data/Cousine-Regular.ttf

-42.9 KB
Binary file not shown.

examples/example_basic_0.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from pathlib import Path
23

34
# core
45
import pilotlight.pilotlight as pl
@@ -34,12 +35,9 @@ def pl_app_load(self):
3435
# Mount directories used by the shader system.
3536
# /shaders points at the Python package shader folder.
3637
# /shader-temp is where compiled/intermediate shader output can go.
37-
plVfsI.mount_directory("/cache", "cache")
38-
plVfsI.mount_directory(
39-
"/shaders",
40-
os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders"
41-
)
42-
plVfsI.mount_directory("/shader-temp", "shader-temp")
38+
plVfsI.mount_directory("/cache", str(Path.cwd()) + "/../cache")
39+
plVfsI.mount_directory("/shaders", os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders")
40+
plVfsI.mount_directory("/shader-temp", str(Path.cwd()) + "/../shader-temp")
4341

4442
# Create and show the OS window.
4543
window_desc = plWindowDesc()

examples/example_basic_1.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from pathlib import Path
23

34
# core
45
import pilotlight.pilotlight as pl
@@ -35,13 +36,10 @@ def pl_app_load(self):
3536
# Mount directories used by the shader system.
3637
# /shaders points at the Python package shader folder.
3738
# /shader-temp is where compiled/intermediate shader output can go.
38-
plVfsI.mount_directory("/data", os.path.dirname(os.path.abspath(pl.__file__)) + "/../data")
39-
plVfsI.mount_directory("/cache", "cache")
40-
plVfsI.mount_directory(
41-
"/shaders",
42-
os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders"
43-
)
44-
plVfsI.mount_directory("/shader-temp", "shader-temp")
39+
plVfsI.mount_directory("/cache", str(Path.cwd()) + "/../cache")
40+
plVfsI.mount_directory("/shaders", os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders")
41+
plVfsI.mount_directory("/shader-temp", str(Path.cwd()) + "/../shader-temp")
42+
plVfsI.mount_directory("/assets", str(Path.cwd()) + "/../../pilotlight/assets")
4543

4644
# Create and show the OS window.
4745
window_desc = plWindowDesc()
@@ -77,7 +75,7 @@ def pl_app_load(self):
7775
tFontConfig.uHOverSampling = 1
7876
tFontConfig.uVOverSampling = 1
7977
tFontConfig.ptRanges = [tFontRange]
80-
self.ptFont = plDrawI.add_font_from_file_ttf(self.ptFontAtlas, tFontConfig, "/data/Cousine-Regular.ttf");
78+
self.ptFont = plDrawI.add_font_from_file_ttf(self.ptFontAtlas, tFontConfig, "/assets/core/fonts/Cousine-Regular.ttf");
8179

8280
self.drawlist = plDrawI.request_2d_drawlist()
8381
self.ptFGLayer = plDrawI.request_2d_layer(self.drawlist)

examples/example_basic_2.py

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import os
22
import math
3+
from pathlib import Path
34

45
# core
56
import pilotlight.pilotlight as pl
67
from pilotlight.pilotlight import *
78
from pilotlight.imgui import *
89
from pilotlight.enums import *
910
from pilotlight.types import *
11+
from pilotlight.pl_script_camera import pl_script_run
1012

1113
class App:
1214

@@ -30,10 +32,10 @@ def pl_app_load(self):
3032
# Mount directories used by the shader/font systems.
3133
package_dir = os.path.dirname(os.path.abspath(pl.__file__))
3234

33-
plVfsI.mount_directory("/data", package_dir + "/../data")
34-
plVfsI.mount_directory("/cache", "cache")
35-
plVfsI.mount_directory("/shaders", package_dir + "/shaders")
36-
plVfsI.mount_directory("/shader-temp", "shader-temp")
35+
plVfsI.mount_directory("/cache", str(Path.cwd()) + "/../cache")
36+
plVfsI.mount_directory("/shaders", os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders")
37+
plVfsI.mount_directory("/shader-temp", str(Path.cwd()) + "/../shader-temp")
38+
plVfsI.mount_directory("/assets", str(Path.cwd()) + "/../../pilotlight/assets")
3739

3840
# Create window.
3941
window_desc = plWindowDesc()
@@ -77,7 +79,7 @@ def pl_app_load(self):
7779
self.ptFont = plDrawI.add_font_from_file_ttf(
7880
self.ptFontAtlas,
7981
tFontConfig,
80-
"/data/Cousine-Regular.ttf"
82+
"/assets/core/fonts/Cousine-Regular.ttf"
8183
)
8284

8385
# Persistent 3D drawlist.
@@ -444,35 +446,7 @@ def pl_app_update(self):
444446

445447
ptIO = plIOI.get_io()
446448

447-
camera_travel_speed = 5.0
448-
camera_rotation_speed = 0.005
449-
450-
dt = ptIO.fDeltaTime
451-
452-
if plIOI.is_key_down(plKey.PL_KEY_W):
453-
plCameraI.translate_local(self.camera, [0.0, 0.0, camera_travel_speed * dt])
454-
455-
if plIOI.is_key_down(plKey.PL_KEY_S):
456-
plCameraI.translate_local(self.camera, [0.0, 0.0, -camera_travel_speed * dt])
457-
458-
if plIOI.is_key_down(plKey.PL_KEY_A):
459-
plCameraI.translate_local(self.camera, [-camera_travel_speed * dt, 0.0, 0.0])
460-
461-
if plIOI.is_key_down(plKey.PL_KEY_D):
462-
plCameraI.translate_local(self.camera, [camera_travel_speed * dt, 0.0, 0.0])
463-
464-
if plIOI.is_key_down(plKey.PL_KEY_R):
465-
plCameraI.translate(self.camera, [0.0, camera_travel_speed * dt, 0.0])
466-
467-
if plIOI.is_key_down(plKey.PL_KEY_F):
468-
plCameraI.translate(self.camera, [0.0, -camera_travel_speed * dt, 0.0])
469-
470-
if plIOI.is_mouse_dragging(plMouseButton.PL_MOUSE_BUTTON_LEFT, 1.0):
471-
tMouseDelta = plIOI.get_mouse_drag_delta(plMouseButton.PL_MOUSE_BUTTON_LEFT, 1.0)
472-
plCameraI.rotate_euler(self.camera, -tMouseDelta.y * camera_rotation_speed, -tMouseDelta.x * camera_rotation_speed, 0.0)
473-
plIOI.reset_mouse_drag_delta(plMouseButton.PL_MOUSE_BUTTON_LEFT)
474-
475-
plCameraI.update(self.camera)
449+
pl_script_run(self.camera)
476450

477451
# Start a new draw frame. This clears/refreshes internal draw state.
478452
plDrawI.new_frame()
@@ -482,7 +456,7 @@ def pl_app_update(self):
482456

483457
overlay = (
484458
"3D plDrawI Python Example\n"
485-
"W/S/A/D: move | R/F: up/down | LMB drag: look\n"
459+
"Unreal Camera Controls\n"
486460
f"FPS: {ptIO.fFrameRate:.1f}"
487461
)
488462

examples/example_basic_3.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import os
2+
from pathlib import Path
3+
4+
# core
5+
import pilotlight.pilotlight as pl
6+
from pilotlight.pilotlight import *
7+
from pilotlight.imgui import *
8+
from pilotlight.enums import *
9+
from pilotlight.types import *
10+
11+
class App:
12+
"""
13+
Simple Pilot Light Python example showing how to:
14+
- create a window
15+
- initialize the starter/shader systems
16+
- draw basic 2D primitives every frame
17+
- organize drawing code in a readable way
18+
"""
19+
20+
def __init__(self):
21+
self.ptWindow = None
22+
self.ptFont = None
23+
24+
# -------------------------------------------------------------------------
25+
# Application lifetime
26+
# -------------------------------------------------------------------------
27+
28+
def pl_app_load(self):
29+
"""
30+
Called once when the app starts.
31+
Set up virtual file system mounts, create a window, and initialize
32+
the Pilot Light systems we want to use.
33+
"""
34+
35+
# Mount directories used by the shader system.
36+
# /shaders points at the Python package shader folder.
37+
# /shader-temp is where compiled/intermediate shader output can go.
38+
plVfsI.mount_directory("/cache", str(Path.cwd()) + "/../cache")
39+
plVfsI.mount_directory("/shaders", os.path.dirname(os.path.abspath(pl.__file__)) + "/shaders")
40+
plVfsI.mount_directory("/shader-temp", str(Path.cwd()) + "/../shader-temp")
41+
plVfsI.mount_directory("/assets", str(Path.cwd()) + "/../../pilotlight/assets")
42+
43+
# Create and show the OS window.
44+
window_desc = plWindowDesc()
45+
window_desc.pcTitle = "Pilot Light Python - Basic Example 0"
46+
window_desc.iXPos = 100
47+
window_desc.iYPos = 100
48+
window_desc.uWidth = 1280
49+
window_desc.uHeight = 720
50+
_, self.ptWindow = plWindowI.create(window_desc)
51+
plWindowI.show(self.ptWindow)
52+
53+
# Initialize the starter extension.
54+
# We explicitly disable the shader ext from the starter flags because
55+
# we are going to initialize the shader system ourselves below.
56+
starter_flags = plStarterFlag.PL_STARTER_FLAGS_ALL_EXTENSIONS
57+
starter_flags &= ~plStarterFlag.PL_STARTER_FLAGS_SHADER_EXT
58+
starter_flags |= plStarterFlag.PL_STARTER_FLAGS_MSAA
59+
60+
plStarterI.initialize(self.ptWindow, starter_flags)
61+
62+
# Initialize shader system.
63+
# This is required even for simple drawing examples because the
64+
# rendering path may still rely on shader compilation/setup.
65+
shader_options = plShaderOptions()
66+
shader_options.pcCacheOutputDirectory = "/shader-temp/"
67+
shader_options.apcDirectories = ["/shaders/"]
68+
shader_options.apcIncludeDirectories = ["/shaders/"]
69+
shader_options.tFlags = (
70+
plShaderFlags.PL_SHADER_FLAGS_AUTO_OUTPUT
71+
| plShaderFlags.PL_SHADER_FLAGS_INCLUDE_DEBUG
72+
| plShaderFlags.PL_SHADER_FLAGS_ALWAYS_COMPILE
73+
)
74+
75+
plShaderI.initialize(shader_options)
76+
77+
# Complete starter initialization after custom systems are ready.
78+
plStarterI.finalize()
79+
80+
ptFontAtlas = plDrawI.get_current_font_atlas()
81+
self.ptFont = plDrawI.get_first_font(ptFontAtlas)
82+
83+
self.ptDevice = plStarterI.get_device()
84+
resourceManagerInit = plResourceManagerInit()
85+
resourceManagerInit.ptDevice = self.ptDevice
86+
plResourceI.initialize(resourceManagerInit)
87+
88+
self.texture_resource = plResourceI.load("/assets/core/textures/sprite_map.png", 0)
89+
self.texture_handle = plResourceI.get_texture(self.texture_resource)
90+
self.texture_bg = plDrawI.create_bind_group_for_texture(self.texture_handle)
91+
92+
def pl_app_shutdown(self):
93+
"""
94+
Called once when the app exits.
95+
Flush GPU work, clean up engine systems, then destroy the window.
96+
"""
97+
98+
plGraphicsI.flush_device(plStarterI.get_device())
99+
plResourceI.cleanup()
100+
plStarterI.cleanup()
101+
102+
plWindowI.destroy(self.ptWindow)
103+
104+
def pl_app_resize(self):
105+
"""
106+
Called when the window changes size.
107+
Let the starter extension rebuild any size-dependent resources.
108+
"""
109+
plStarterI.resize()
110+
111+
# -------------------------------------------------------------------------
112+
# Per-frame update
113+
# -------------------------------------------------------------------------
114+
115+
def pl_app_update(self):
116+
"""
117+
Called once per frame.
118+
This is where all drawing for the frame happens.
119+
"""
120+
121+
# Begin the frame. If it returns False, skip rendering this frame.
122+
if not plStarterI.begin_frame():
123+
return
124+
125+
plResourceI.new_frame()
126+
127+
# Foreground fgLayer is a convenient draw list for 2D overlay-style
128+
# rendering.
129+
fgLayer = plStarterI.get_foreground_layer()
130+
131+
plDrawI.add_bezier_quad(
132+
fgLayer,
133+
[120.0, 420.0], # start
134+
[260.0, 320.0], # control
135+
[420.0, 450.0], # end
136+
0, # segment count (0 = automatic/default)
137+
plDrawLineOptions(PL_COLOR_32_BLUE)
138+
)
139+
140+
# Cubic bezier with thicker line
141+
plDrawI.add_bezier_cubic(
142+
fgLayer,
143+
[120.0, 560.0], # start
144+
[220.0, 460.0], # control 1
145+
[360.0, 660.0], # control 2
146+
[460.0, 540.0], # end
147+
0, # segment count
148+
plDrawLineOptions(PL_COLOR_32_RED, 3.0)
149+
)
150+
151+
plDrawI.add_image(fgLayer, self.texture_bg, [0, 0], [500, 500])
152+
153+
# Submit/present the frame.
154+
plStarterI.end_frame()
155+
156+
157+
# Run the application.
158+
pl_run(App())

extensions/pl_animation_ext_m.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,51 @@ animation_register_ecs_system(PyObject* self)
2727
Py_RETURN_NONE;
2828
}
2929

30+
PyObject*
31+
animation_run_animation_update_system(PyObject* self, PyObject* args)
32+
{
33+
static const char* apcKeywords[] = {
34+
"library",
35+
"deltaTime",
36+
NULL,
37+
};
38+
39+
PyObject* ptPyLibrary = NULL;
40+
float fDeltaTime = 0.0f;
41+
if (!pl_parse("Of", (const char**)apcKeywords, args, NULL, __FUNCTION__,
42+
&ptPyLibrary, &fDeltaTime))
43+
return NULL;
44+
45+
plComponentLibrary* ptCompLibrary = PyCapsule_GetPointer(ptPyLibrary, "plComponentLibrary");
46+
47+
gptAnimation->run_animation_update_system(ptCompLibrary, fDeltaTime);
48+
Py_RETURN_NONE;
49+
}
50+
51+
PyObject*
52+
animation_run_inverse_kinematics_update_system(PyObject* self, PyObject* args)
53+
{
54+
static const char* apcKeywords[] = {
55+
"library",
56+
NULL,
57+
};
58+
59+
PyObject* ptPyLibrary = NULL;
60+
if (!pl_parse("O", (const char**)apcKeywords, args, NULL, __FUNCTION__,
61+
&ptPyLibrary))
62+
return NULL;
63+
64+
plComponentLibrary* ptCompLibrary = PyCapsule_GetPointer(ptPyLibrary, "plComponentLibrary");
65+
66+
gptAnimation->run_inverse_kinematics_update_system(ptCompLibrary);
67+
Py_RETURN_NONE;
68+
}
69+
3070
static PyMethodDef gatCommandsplAnimationI[] =
3171
{
3272
{"register_ecs_system", (PyCFunction)animation_register_ecs_system, METH_NOARGS | METH_STATIC, NULL},
73+
{"run_animation_update_system", (PyCFunction)animation_run_animation_update_system, METH_VARARGS | METH_STATIC, NULL},
74+
{"run_inverse_kinematics_update_system", (PyCFunction)animation_run_inverse_kinematics_update_system, METH_VARARGS | METH_STATIC, NULL},
3375
{NULL, NULL, 0, NULL}
3476
};
3577

0 commit comments

Comments
 (0)