ncca-ngl 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,12 @@
1
+ __version__ = "0.1.0"
2
+
3
+
4
+ from .lookatwidget import LookAtWidget
5
+ from .rgbacolourwidget import RGBAColourWidget
6
+ from .rgbcolourwidget import RGBColourWidget
7
+ from .transformwidget import TransformWidget
8
+ from .vec2widget import Vec2Widget
9
+ from .vec3widget import Vec3Widget
10
+ from .vec4widget import Vec4Widget
11
+
12
+ __all__ = ["Vec2Widget", "Vec3Widget", "Vec4Widget", "TransformWidget", "LookAtWidget", "RGBColourWidget"]
@@ -0,0 +1,77 @@
1
+ import sys
2
+
3
+ from PySide6.QtWidgets import QApplication, QDialog, QGridLayout, QLabel
4
+
5
+ from ncca.ngl import Vec2, Vec3, Vec4
6
+ from ncca.ngl.widgets import (
7
+ LookAtWidget,
8
+ RGBAColourWidget,
9
+ RGBColourWidget,
10
+ TransformWidget,
11
+ Vec2Widget,
12
+ Vec3Widget,
13
+ Vec4Widget,
14
+ )
15
+
16
+
17
+ class SimpleDialog(QDialog):
18
+ def __init__(self, parent=None):
19
+ super(SimpleDialog, self).__init__(parent)
20
+ self.setWindowTitle("PyNGL ncca.widgets library ")
21
+ self.setMinimumWidth(200)
22
+ layout = QGridLayout()
23
+
24
+ self.vec2_widget = Vec2Widget("Vec2 Widget", Vec2(1, 2), self)
25
+ self.vec2_widget.set_x_range(-1, 1)
26
+ self.vec2_widget.set_y_range(-2, 2)
27
+ layout.addWidget(self.vec2_widget, 0, 0)
28
+ self.vec2_label = QLabel("[0.0,0.0]")
29
+ layout.addWidget(self.vec2_label, 0, 1)
30
+ self.vec2_widget.valueChanged.connect(self._update_vec2)
31
+
32
+ self.vec3_widget = Vec3Widget("Vec3 Widget", Vec3(1, 2, 3), self)
33
+ self.vec3_widget.set_y_range(-2, 2)
34
+ self.vec3_widget.set_z_range(-3, 3)
35
+ layout.addWidget(self.vec3_widget, 1, 0)
36
+ self.vec3_label = QLabel("[0.0,0.0,0.0]")
37
+ layout.addWidget(self.vec3_label, 1, 1)
38
+ self.vec3_widget.valueChanged.connect(self._update_vec3)
39
+
40
+ self.vec4_widget = Vec4Widget("Vec4 Widget", Vec4(1, 2, 3, 1.0), self)
41
+ self.vec4_widget.set_y_range(-2, 2)
42
+ self.vec4_widget.set_z_range(-3, 3)
43
+ layout.addWidget(self.vec4_widget, 2, 0)
44
+ self.vec4_label = QLabel("[0.0,0.0,0.0,1.0]")
45
+ layout.addWidget(self.vec4_label, 2, 1)
46
+ self.vec4_widget.valueChanged.connect(self._update_vec4)
47
+
48
+ self.transform_widget = TransformWidget("Transform Widget", self)
49
+ layout.addWidget(self.transform_widget, 3, 0)
50
+
51
+ self.lookat = LookAtWidget("Look At", parent=self)
52
+ layout.addWidget(self.lookat, 4, 0)
53
+
54
+ self.rgb_colour_widget = RGBColourWidget("RGB Colour Widget", 1.0, 0.0, 0.0, self)
55
+ layout.addWidget(self.rgb_colour_widget, 5, 0)
56
+ self.rgba_colour_widget = RGBAColourWidget("RGB Colour Widget", 1.0, 0.0, 0.0, 1.0, self)
57
+ layout.addWidget(self.rgba_colour_widget, 6, 0)
58
+
59
+ self.setLayout(layout)
60
+
61
+ def _update_vec3(self, value):
62
+ self.vec3_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}, {value.z:0.2f}]")
63
+
64
+ def _update_vec2(self, value):
65
+ self.vec2_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}]")
66
+
67
+ def _update_vec4(self, value):
68
+ self.vec4_label.setText(f"[{value.x:0.2f}, {value.y:0.2f}, {value.z:0.2f}, {value.w:0.2f}]")
69
+
70
+
71
+ if __name__ == "__main__":
72
+ app = QApplication(sys.argv)
73
+ print("NCCA Widgets")
74
+
75
+ dialog = SimpleDialog()
76
+ dialog.show()
77
+ app.exec()
@@ -0,0 +1,27 @@
1
+ #version 330 core
2
+ out vec4 FragColor;
3
+ in vec3 FragPos;
4
+ in vec3 Normal;
5
+ uniform vec3 light_pos;
6
+ uniform vec3 view_pos;
7
+ uniform vec3 light_color;
8
+ uniform vec3 object_color;
9
+ void main()
10
+ {
11
+ // Ambient
12
+ float ambient_strength = 0.1;
13
+ vec3 ambient = ambient_strength * light_color;
14
+ // Diffuse
15
+ vec3 norm = normalize(Normal);
16
+ vec3 light_dir = normalize(light_pos - FragPos);
17
+ float diff = max(dot(norm, light_dir), 0.0);
18
+ vec3 diffuse = diff * light_color;
19
+ // Specular
20
+ float specular_strength = 0.5;
21
+ vec3 view_dir = normalize(view_pos - FragPos);
22
+ vec3 reflect_dir = reflect(-light_dir, norm);
23
+ float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);
24
+ vec3 specular = specular_strength * spec * light_color;
25
+ vec3 result = (ambient + diffuse + specular) * object_color;
26
+ FragColor = vec4(result, 1.0);
27
+ }
@@ -0,0 +1,14 @@
1
+ #version 330 core
2
+ layout (location = 0) in vec3 aPos;
3
+ layout (location = 1) in vec3 aNormal;
4
+ out vec3 FragPos;
5
+ out vec3 Normal;
6
+ uniform mat4 model;
7
+ uniform mat4 MVP;
8
+ uniform mat3 normal_matrix;
9
+ void main()
10
+ {
11
+ FragPos = vec3(model * vec4(aPos, 1.0));
12
+ Normal = normal_matrix * aNormal;
13
+ gl_Position = MVP * vec4(aPos, 1.0);
14
+ }
@@ -0,0 +1,7 @@
1
+ #version 330 core
2
+ out vec3 FragColor;
3
+ uniform vec3 face_id;
4
+ void main()
5
+ {
6
+ FragColor = face_id;
7
+ }
@@ -0,0 +1,7 @@
1
+ #version 330 core
2
+ layout (location = 0) in vec3 aPos;
3
+ uniform mat4 MVP;
4
+ void main()
5
+ {
6
+ gl_Position = MVP * vec4(aPos, 1.0);
7
+ }
@@ -0,0 +1,77 @@
1
+ from PySide6.QtCore import Property, QSignalBlocker, Qt, Signal, Slot
2
+ from PySide6.QtWidgets import QComboBox, QFrame, QLabel, QToolButton, QVBoxLayout, QWidget
3
+
4
+ from ncca.ngl import Mat4, Vec3, look_at
5
+
6
+ from .vec3widget import Vec3Widget
7
+
8
+
9
+ class LookAtWidget(QFrame):
10
+ """A widget for displaying and editing a Transform object, with foldable sections."""
11
+
12
+ valueChanged = Signal(Mat4)
13
+
14
+ def __init__(self, name: str, eye=Vec3(2, 2, 2), look=Vec3(0, 0, 0), parent: QWidget | None = None) -> None:
15
+ """
16
+ Args:
17
+ name: The name of the widget.
18
+ parent: The parent widget.
19
+ """
20
+ super().__init__(parent)
21
+ self.setFrameShape(QFrame.Shape.StyledPanel)
22
+ self._name = name
23
+ self._view = Mat4()
24
+ main_layout = QVBoxLayout(self)
25
+ main_layout.setContentsMargins(2, 2, 2, 2)
26
+ main_layout.setSpacing(0)
27
+
28
+ self._toggle_button = QToolButton(self)
29
+ self._toggle_button.setText(self._name)
30
+ self._toggle_button.setCheckable(True)
31
+ self._toggle_button.setChecked(True)
32
+ self._toggle_button.setStyleSheet("QToolButton { border: none; }")
33
+ self._toggle_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
34
+ self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
35
+ self._toggle_button.clicked.connect(self.toggle_collapsed)
36
+
37
+ self._content_widget = QWidget(self)
38
+ content_layout = QVBoxLayout(self._content_widget)
39
+ content_layout.setContentsMargins(0, 0, 0, 0)
40
+
41
+ self._eye = Vec3Widget("Eye", eye, self)
42
+ self._look = Vec3Widget("Look", look, self)
43
+ self._up = QComboBox(self)
44
+ for v in ["y-up", "x-up", "z-up"]:
45
+ self._up.addItem(v)
46
+ self._eye.valueChanged.connect(self._update_matrix)
47
+ self._look.valueChanged.connect(self._update_matrix)
48
+ self._up.currentIndexChanged.connect(self._update_matrix)
49
+ content_layout.addWidget(self._eye)
50
+ content_layout.addWidget(self._look)
51
+ content_layout.addWidget(QLabel("World Up"))
52
+ content_layout.addWidget(self._up)
53
+ main_layout.addWidget(self._toggle_button)
54
+ main_layout.addWidget(self._content_widget)
55
+
56
+ def toggle_collapsed(self, checked: bool) -> None:
57
+ """Toggles the visibility of the content widget."""
58
+ if checked:
59
+ self._toggle_button.setArrowType(Qt.ArrowType.DownArrow)
60
+ self._content_widget.setVisible(True)
61
+ else:
62
+ self._toggle_button.setArrowType(Qt.ArrowType.RightArrow)
63
+ self._content_widget.setVisible(False)
64
+
65
+ def _update_matrix(self) -> None:
66
+ """Updates the view matrix based on the widget values."""
67
+ eye = self._eye.value
68
+ look = self._look.value
69
+ world_up = [Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(0, 0, 1)]
70
+ up = world_up[self._up.currentIndex()]
71
+
72
+ self._view = look_at(eye, look, up)
73
+ self.valueChanged.emit(self._view)
74
+
75
+ def view(self) -> Mat4:
76
+ """Returns the current view matrix."""
77
+ return self._view
@@ -0,0 +1,7 @@
1
+ from PySide6.QtCore import Property, QSignalBlocker, Signal
2
+ from PySide6.QtWidgets import QDoubleSpinBox, QFrame, QHBoxLayout, QLabel, QWidget
3
+
4
+ from ncca.ngl import Mat4
5
+
6
+
7
+ class Mat4ViewWidget(QFrame):
@@ -0,0 +1,157 @@
1
+ from PySide6.QtCore import Property, QSignalBlocker, Signal
2
+ from PySide6.QtGui import QColor
3
+ from PySide6.QtWidgets import (
4
+ QColorDialog,
5
+ QDoubleSpinBox,
6
+ QFrame,
7
+ QHBoxLayout,
8
+ QLabel,
9
+ QPushButton,
10
+ QWidget,
11
+ )
12
+
13
+ from ncca.ngl import Vec4
14
+
15
+
16
+ class RGBAColourWidget(QFrame):
17
+ """A widget for displaying and editing a Vec4 object."""
18
+
19
+ colourChanged = Signal(Vec4)
20
+ rValueChanged = Signal(float)
21
+ gValueChanged = Signal(float)
22
+ bValueChanged = Signal(float)
23
+ aValueChanged = Signal(float)
24
+
25
+ def __init__(self, name: str, r: float, g: float, b: float, a: float, parent: QWidget | None = None) -> None:
26
+ """
27
+ Args:
28
+ name: The name of the widget.
29
+ r: The initial red component of the colour.
30
+ g: The initial green component of the colour.
31
+ b: The initial blue component of the colour.
32
+ a: The initial alpha component of the colour.
33
+ parent: The parent widget.
34
+ """
35
+ super().__init__(parent)
36
+ self.setFrameShape(QFrame.Shape.StyledPanel)
37
+ self._colour = Vec4(r, g, b, a)
38
+ self._name = name
39
+ layout = QHBoxLayout()
40
+
41
+ self.r_spinbox = self._create_spinbox(self._colour.x)
42
+ self.g_spinbox = self._create_spinbox(self._colour.y)
43
+ self.b_spinbox = self._create_spinbox(self._colour.z)
44
+ self.a_spinbox = self._create_spinbox(self._colour.w)
45
+ self._label = QLabel(self._name)
46
+ self._color_button = QPushButton()
47
+ self._color_button.setFixedSize(20, 20)
48
+ self._color_button.clicked.connect(self._show_color_dialog)
49
+ self._update_button_color()
50
+
51
+ layout.addWidget(self._label)
52
+ layout.addWidget(self.r_spinbox)
53
+ layout.addWidget(self.g_spinbox)
54
+ layout.addWidget(self.b_spinbox)
55
+ layout.addWidget(self.a_spinbox)
56
+ layout.addWidget(self._color_button)
57
+ self.setLayout(layout)
58
+
59
+ def _create_spinbox(self, value: float) -> QDoubleSpinBox:
60
+ """Helper method to create and configure a QDoubleSpinBox.
61
+
62
+ Args:
63
+ value: The initial value of the spinbox.
64
+
65
+ Returns:
66
+ A configured QDoubleSpinBox.
67
+ """
68
+ spinbox = QDoubleSpinBox()
69
+ spinbox.setValue(value)
70
+ spinbox.setRange(0.0, 1.0)
71
+ spinbox.setSingleStep(0.01)
72
+ spinbox.valueChanged.connect(self._on_value_changed)
73
+ return spinbox
74
+
75
+ def colour(self) -> Vec4:
76
+ """
77
+ Returns:
78
+ The current value of the widget.
79
+ """
80
+ return self._colour
81
+
82
+ def _on_value_changed(self, value: float) -> None:
83
+ """This slot is called when the value of a spinbox changes.
84
+
85
+ Args:
86
+ value: The new value of the spinbox.
87
+ """
88
+ sender = self.sender()
89
+ if sender == self.r_spinbox:
90
+ self._colour.x = value
91
+ self.rValueChanged.emit(value)
92
+ elif sender == self.g_spinbox:
93
+ self._colour.y = value
94
+ self.gValueChanged.emit(value)
95
+ elif sender == self.b_spinbox:
96
+ self._colour.z = value
97
+ self.bValueChanged.emit(value)
98
+ elif sender == self.a_spinbox:
99
+ self._colour.w = value
100
+ self.aValueChanged.emit(value)
101
+ # emit the Vec4 value changed signal
102
+ self.colourChanged.emit(self._colour)
103
+ self._update_button_color()
104
+
105
+ def set_colour(self, value: Vec4) -> None:
106
+ """Sets the value of the widget.
107
+
108
+ Args:
109
+ value: The new value of the widget.
110
+ """
111
+ with (
112
+ QSignalBlocker(self.r_spinbox),
113
+ QSignalBlocker(self.g_spinbox),
114
+ QSignalBlocker(self.b_spinbox),
115
+ QSignalBlocker(self.a_spinbox),
116
+ ):
117
+ self.r_spinbox.setValue(value.x)
118
+ self.g_spinbox.setValue(value.y)
119
+ self.b_spinbox.setValue(value.z)
120
+ self.a_spinbox.setValue(value.w)
121
+ self._colour = value
122
+ self.colourChanged.emit(self._colour)
123
+ self._update_button_color()
124
+
125
+ def _update_button_color(self) -> None:
126
+ """Updates the background color of the color button."""
127
+ color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z, self._colour.w)
128
+ self._color_button.setStyleSheet(f"background-color: {color.name(QColor.NameFormat.HexArgb)}")
129
+
130
+ def _show_color_dialog(self) -> None:
131
+ """Shows a QColorDialog to select a new color."""
132
+ current_color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z, self._colour.w)
133
+ color = QColorDialog.getColor(
134
+ current_color, self, "Select Color", options=QColorDialog.ColorDialogOption.ShowAlphaChannel
135
+ )
136
+ if color.isValid():
137
+ new_colour = Vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF())
138
+ self.set_colour(new_colour)
139
+
140
+ def name(self) -> str:
141
+ """
142
+ Returns:
143
+ The name of the widget.
144
+ """
145
+ return self._name
146
+
147
+ def set_name(self, name: str) -> None:
148
+ """Sets the name of the widget.
149
+
150
+ Args:
151
+ name: The new name of the widget.
152
+ """
153
+ self._name = name
154
+ self._label.setText(name)
155
+
156
+ value = Property(Vec4, colour, set_colour)
157
+ name = Property(str, name, set_name)
@@ -0,0 +1,143 @@
1
+ from PySide6.QtCore import Property, QSignalBlocker, Signal
2
+ from PySide6.QtGui import QColor
3
+ from PySide6.QtWidgets import (
4
+ QColorDialog,
5
+ QDoubleSpinBox,
6
+ QFrame,
7
+ QHBoxLayout,
8
+ QLabel,
9
+ QPushButton,
10
+ QWidget,
11
+ )
12
+
13
+ from ncca.ngl import Vec3
14
+
15
+
16
+ class RGBColourWidget(QFrame):
17
+ """A widget for displaying and editing a Vec3 object."""
18
+
19
+ colourChanged = Signal(Vec3)
20
+ rValueChanged = Signal(float)
21
+ gValueChanged = Signal(float)
22
+ bValueChanged = Signal(float)
23
+
24
+ def __init__(self, name: str, r: float, g: float, b: float, parent: QWidget | None = None) -> None:
25
+ """
26
+ Args:
27
+ name: The name of the widget.
28
+ r: The initial red component of the colour.
29
+ g: The initial green component of the colour.
30
+ b: The initial blue component of the colour.
31
+ parent: The parent widget.
32
+ """
33
+ super().__init__(parent)
34
+ self.setFrameShape(QFrame.Shape.StyledPanel)
35
+ self._colour = Vec3(r, g, b)
36
+ self._name = name
37
+ layout = QHBoxLayout()
38
+
39
+ self.r_spinbox = self._create_spinbox(self._colour.x)
40
+ self.g_spinbox = self._create_spinbox(self._colour.y)
41
+ self.b_spinbox = self._create_spinbox(self._colour.z)
42
+
43
+ self._label = QLabel(self._name)
44
+ self._color_button = QPushButton()
45
+ self._color_button.setFixedSize(20, 20)
46
+ self._color_button.clicked.connect(self._show_color_dialog)
47
+ self._update_button_color()
48
+
49
+ layout.addWidget(self._label)
50
+ layout.addWidget(self.r_spinbox)
51
+ layout.addWidget(self.g_spinbox)
52
+ layout.addWidget(self.b_spinbox)
53
+ layout.addWidget(self._color_button)
54
+ self.setLayout(layout)
55
+
56
+ def _create_spinbox(self, value: float) -> QDoubleSpinBox:
57
+ """Helper method to create and configure a QDoubleSpinBox.
58
+
59
+ Args:
60
+ value: The initial value of the spinbox.
61
+
62
+ Returns:
63
+ A configured QDoubleSpinBox.
64
+ """
65
+ spinbox = QDoubleSpinBox()
66
+ spinbox.setValue(value)
67
+ spinbox.setRange(0.0, 1.0)
68
+ spinbox.setSingleStep(0.01)
69
+ spinbox.valueChanged.connect(self._on_value_changed)
70
+ return spinbox
71
+
72
+ def colour(self) -> Vec3:
73
+ """
74
+ Returns:
75
+ The current value of the widget.
76
+ """
77
+ return self._colour
78
+
79
+ def _on_value_changed(self, value: float) -> None:
80
+ """This slot is called when the value of a spinbox changes.
81
+
82
+ Args:
83
+ value: The new value of the spinbox.
84
+ """
85
+ sender = self.sender()
86
+ if sender == self.r_spinbox:
87
+ self._colour.x = value
88
+ self.rValueChanged.emit(value)
89
+ elif sender == self.g_spinbox:
90
+ self._colour.y = value
91
+ self.gValueChanged.emit(value)
92
+ elif sender == self.b_spinbox:
93
+ self._colour.z = value
94
+ self.bValueChanged.emit(value)
95
+ # emit the Vec3 value changed signal
96
+ self.colourChanged.emit(self._colour)
97
+ self._update_button_color()
98
+
99
+ def set_colour(self, value: Vec3) -> None:
100
+ """Sets the value of the widget.
101
+
102
+ Args:
103
+ value: The new value of the widget.
104
+ """
105
+ with QSignalBlocker(self.r_spinbox), QSignalBlocker(self.g_spinbox), QSignalBlocker(self.b_spinbox):
106
+ self.r_spinbox.setValue(value.x)
107
+ self.g_spinbox.setValue(value.y)
108
+ self.b_spinbox.setValue(value.z)
109
+ self._colour = value
110
+ self.colourChanged.emit(self._colour)
111
+ self._update_button_color()
112
+
113
+ def _update_button_color(self) -> None:
114
+ """Updates the background color of the color button."""
115
+ color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
116
+ self._color_button.setStyleSheet(f"background-color: {color.name()}")
117
+
118
+ def _show_color_dialog(self) -> None:
119
+ """Shows a QColorDialog to select a new color."""
120
+ current_color = QColor.fromRgbF(self._colour.x, self._colour.y, self._colour.z)
121
+ color = QColorDialog.getColor(current_color, self, "Select Color")
122
+ if color.isValid():
123
+ new_colour = Vec3(color.redF(), color.greenF(), color.blueF())
124
+ self.set_colour(new_colour)
125
+
126
+ def name(self) -> str:
127
+ """
128
+ Returns:
129
+ The name of the widget.
130
+ """
131
+ return self._name
132
+
133
+ def set_name(self, name: str) -> None:
134
+ """Sets the name of the widget.
135
+
136
+ Args:
137
+ name: The new name of the widget.
138
+ """
139
+ self._name = name
140
+ self._label.setText(name)
141
+
142
+ value = Property(Vec3, colour, set_colour)
143
+ name = Property(str, name, set_name)