431
|
1 import std/strformat
|
433
|
2 import std/tables
|
431
|
3
|
430
|
4 import ./core
|
431
|
5 import ./mesh
|
433
|
6 import ./material
|
|
7 import ./vulkan/shader
|
434
|
8 import ./events
|
430
|
9
|
|
10 const
|
433
|
11 # font shader
|
431
|
12 SHADER_ATTRIB_PREFIX = "semicon_panel_"
|
|
13 MAX_PANEL_MATERIALS = 10
|
433
|
14 POSITION_ATTRIB = SHADER_ATTRIB_PREFIX & "position"
|
|
15 UV_ATTRIB = SHADER_ATTRIB_PREFIX & "uv"
|
|
16 PANEL_MATERIAL_TYPE* = MaterialType(
|
|
17 name: "default-panel-material-type",
|
|
18 vertexAttributes: {TRANSFORM_ATTRIB: Mat4F32, POSITION_ATTRIB: Vec3F32, UV_ATTRIB: Vec2F32}.toTable,
|
|
19 attributes: {"panelTexture": TextureType, "color": Vec4F32}.toTable,
|
|
20 )
|
|
21 PANEL_SHADER* = createShaderConfiguration(
|
|
22 inputs = [
|
|
23 attr[Mat4](TRANSFORM_ATTRIB, memoryPerformanceHint = PreferFastWrite, perInstance = true),
|
|
24 attr[Vec3f](POSITION_ATTRIB, memoryPerformanceHint = PreferFastWrite),
|
|
25 attr[Vec2f](UV_ATTRIB, memoryPerformanceHint = PreferFastWrite),
|
|
26 attr[uint16](MATERIALINDEX_ATTRIBUTE, memoryPerformanceHint = PreferFastRead, perInstance = true),
|
|
27 ],
|
|
28 intermediates = [
|
|
29 attr[Vec2f]("uvFrag"),
|
|
30 attr[uint16]("materialIndexOut", noInterpolation = true)
|
|
31 ],
|
|
32 outputs = [attr[Vec4f]("color")],
|
444
|
33 uniforms = [attr[Vec4f]("color", arrayCount = MAX_PANEL_MATERIALS), attr[float32](ASPECT_RATIO_ATTRIBUTE)],
|
433
|
34 samplers = [attr[Texture]("panelTexture", arrayCount = MAX_PANEL_MATERIALS)],
|
|
35 vertexCode = &"""
|
444
|
36 gl_Position = vec4({POSITION_ATTRIB}.x, {POSITION_ATTRIB}.y * Uniforms.{ASPECT_RATIO_ATTRIBUTE}, {POSITION_ATTRIB}.z, 1.0) * {TRANSFORM_ATTRIB};
|
433
|
37 uvFrag = {UV_ATTRIB};
|
|
38 materialIndexOut = {MATERIALINDEX_ATTRIBUTE};
|
|
39 """,
|
|
40 fragmentCode = &"""color = Uniforms.color[materialIndexOut] * texture(panelTexture[materialIndexOut], uvFrag);"""
|
|
41 )
|
430
|
42
|
|
43 var instanceCounter = 0
|
|
44
|
|
45 type
|
|
46 Panel* = object
|
431
|
47 texture: Texture
|
430
|
48 horizontalAlignment: HorizontalAlignment = Center
|
|
49 verticalAlignment: VerticalAlignment = Center
|
|
50 dirty: bool
|
444
|
51 mesh*: Mesh
|
434
|
52 # input handling
|
|
53 onMouseDown*: proc(panel: var Panel, buttons: set[MouseButton])
|
|
54 onMouseUp*: proc(panel: var Panel, buttons: set[MouseButton])
|
|
55 onMouseEnter*: proc(panel: var Panel)
|
|
56 onMouseMove*: proc(panel: var Panel)
|
|
57 onMouseLeave*: proc(panel: var Panel)
|
|
58 hasMouse*: bool
|
430
|
59
|
433
|
60 proc `$`*(panel: Panel): string =
|
444
|
61 &"Panel {panel.mesh}"
|
433
|
62
|
|
63 proc refresh*(panel: var Panel) =
|
|
64 if not panel.dirty:
|
|
65 return
|
|
66
|
|
67 var
|
|
68 offsetX = case panel.horizontalAlignment
|
444
|
69 of Left: 0.5
|
433
|
70 of Center: 0
|
444
|
71 of Right: -0.5
|
433
|
72 offsetY = case panel.verticalAlignment
|
444
|
73 of Top: 0.5
|
433
|
74 of Center: 0
|
444
|
75 of Bottom: -0.5
|
433
|
76
|
444
|
77 panel.mesh[POSITION_ATTRIB, 0] = newVec3f(-0.5 + offsetX, -0.5 + offsetY)
|
|
78 panel.mesh[POSITION_ATTRIB, 1] = newVec3f(+0.5 + offsetX, -0.5 + offsetY)
|
|
79 panel.mesh[POSITION_ATTRIB, 2] = newVec3f(+0.5 + offsetX, +0.5 + offsetY)
|
|
80 panel.mesh[POSITION_ATTRIB, 3] = newVec3f(-0.5 + offsetX, +0.5 + offsetY)
|
433
|
81
|
|
82 panel.dirty = false
|
|
83
|
434
|
84 proc initPanel*(
|
444
|
85 transform = Unit4,
|
434
|
86 color = newVec4f(1, 1, 1, 1),
|
|
87 texture = EMPTY_TEXTURE,
|
|
88 horizontalAlignment = HorizontalAlignment.Center,
|
|
89 verticalAlignment = VerticalAlignment.Center,
|
|
90 onMouseDown: proc(panel: var Panel, buttons: set[MouseButton]) = nil,
|
|
91 onMouseUp: proc(panel: var Panel, buttons: set[MouseButton]) = nil,
|
|
92 onMouseEnter: proc(panel: var Panel) = nil,
|
|
93 onMouseMove: proc(panel: var Panel) = nil,
|
|
94 onMouseLeave: proc(panel: var Panel) = nil,
|
|
95 ): Panel =
|
431
|
96
|
434
|
97 result = Panel(
|
|
98 texture: texture,
|
|
99 horizontalAlignment: horizontalAlignment,
|
|
100 verticalAlignment: verticalAlignment,
|
|
101 onMouseDown: onMouseDown,
|
|
102 onMouseUp: onMouseUp,
|
|
103 onMouseEnter: onMouseEnter,
|
|
104 onMouseMove: onMouseMove,
|
|
105 onMouseLeave: onMouseLeave,
|
444
|
106 dirty: true,
|
434
|
107 )
|
431
|
108
|
433
|
109 result.mesh = newMesh(
|
444
|
110 name = &"panel-{instanceCounter}",
|
433
|
111 positions = newSeq[Vec3f](4),
|
431
|
112 indices = @[
|
|
113 [uint16(0), uint16(1), uint16(2)],
|
|
114 [uint16(2), uint16(3), uint16(0)],
|
433
|
115 ],
|
444
|
116 uvs = @[newVec2f(0, 1), newVec2f(1, 1), newVec2f(1, 0), newVec2f(0, 0)],
|
|
117 transform = transform
|
433
|
118 )
|
|
119 result.mesh[].renameAttribute("position", POSITION_ATTRIB)
|
|
120 result.mesh[].renameAttribute("uv", UV_ATTRIB)
|
|
121 result.mesh.material = initMaterialData(
|
|
122 theType = PANEL_MATERIAL_TYPE,
|
|
123 name = "Panel material",
|
|
124 attributes = {"panelTexture": initDataList(@[texture]), "color": initDataList(@[color])},
|
|
125 )
|
|
126 inc instanceCounter
|
|
127 result.refresh()
|
431
|
128
|
433
|
129 proc color*(panel: Panel): Vec4f =
|
|
130 panel.mesh.material["color", 0, Vec4f]
|
|
131 proc `color=`*(panel: var Panel, value: Vec4f) =
|
|
132 if value != panel.color:
|
|
133 panel.mesh.material["color", 0] = value
|
|
134
|
430
|
135 proc horizontalAlignment*(panel: Panel): HorizontalAlignment =
|
|
136 panel.horizontalAlignment
|
|
137 proc `horizontalAlignment=`*(panel: var Panel, value: HorizontalAlignment) =
|
|
138 if value != panel.horizontalAlignment:
|
|
139 panel.horizontalAlignment = value
|
|
140 panel.dirty = true
|
|
141
|
|
142 proc verticalAlignment*(panel: Panel): VerticalAlignment =
|
|
143 panel.verticalAlignment
|
|
144 proc `verticalAlignment=`*(panel: var Panel, value: VerticalAlignment) =
|
|
145 if value != panel.verticalAlignment:
|
|
146 panel.verticalAlignment = value
|
|
147 panel.dirty = true
|
|
148
|
444
|
149 proc contains*(panel: Panel, p: Vec2f, aspectRatio: float32): bool =
|
434
|
150 let
|
444
|
151 cursor = panel.mesh.transform.inversed * p.toVec3
|
|
152 p1 = panel.mesh[POSITION_ATTRIB, 0, Vec3f]
|
|
153 p2 = panel.mesh[POSITION_ATTRIB, 2, Vec3f]
|
434
|
154 left = min(p1.x, p2.x)
|
|
155 right = max(p1.x, p2.x)
|
444
|
156 top = min(p1.y * aspectRatio, p2.y * aspectRatio)
|
|
157 bottom = max(p1.y * aspectRatio, p2.y * aspectRatio)
|
434
|
158 return left <= cursor.x and cursor.x <= right and top <= cursor.y and cursor.y <= bottom
|