-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi_primitives.go
366 lines (316 loc) · 11.5 KB
/
api_primitives.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
package vgl
import (
"math"
"github.com/vulkan-go/vulkan"
"github.com/go-glx/glx"
"github.com/go-glx/vgl/internal/gpu/vlk"
)
// Api design
// -----------------------------------------------------------------------------
// Draw2dCircle( p *Params2dCircle )
// ^^^^ ^^^^^^
// | ^^ |
// const | figure
// 2d/3d
//
// 1) all method name MUST start with Draw
// 2) next is 2d/3d API logic splitter.
// - 2d - current API
// - 3d - reserved for feature
// 3) figure is buildIn shader type (point, line, triangle, circle, rect, texture)
// 4) params called exactly as method, but "Params" prefix instead of "Draw"
// 5) all params struct default golang values should be some valid value (and good defaults)
// -----------------------------------------------------------------------------
// Params2dPoint is input for Draw2dPoint
type Params2dPoint struct {
Pos glx.Vec2 // pixel position from top,left corner of surface
Color glx.Color // pixel color
NoCulling bool // will send render command to GPU, even if all vertexes outside of visible screen
}
// Draw2dPoint will draw single point on current surface with current blend mode
// slow draw call, should be used only for editor/debug draw/gizmos, etc...
func (r *Render) Draw2dPoint(p *Params2dPoint) {
localPos := r.toLocalSpace2d(p.Pos)
if !p.NoCulling && !r.cullingPoint(localPos) {
return
}
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeFill,
}
r.api.Draw(buildInShaderPoint, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{
pos: localPos,
color: p.Color.VecRGBA(),
},
},
})
}
// -----------------------------------------------------------------------------
// Params2dLine is input for Draw2dLine
type Params2dLine struct {
Pos [2]glx.Vec2 // pixel positions from top,left corner of surface
Color glx.Color // line color
ColorGradient [2]glx.Color // color for each vertex
ColorUseGradient bool // will use ColorGradient instead of Color
Width float32 // default=1px; max=32px; line width (1px is only guaranteed to fast GPU render).
NoCulling bool // will send render command to GPU, even if all vertexes outside of visible screen
}
// Draw2dLine will draw line on current surface with current blend mode
func (r *Render) Draw2dLine(p *Params2dLine) {
if p.Width < 1 {
p.Width = 1
}
if p.Width > 32 {
p.Width = 32
}
localPos := [2]glx.Vec2{
r.toLocalSpace2d(p.Pos[0]),
r.toLocalSpace2d(p.Pos[1]),
}
localColor := [2]glx.Vec4{}
if p.ColorUseGradient {
localColor[0] = p.ColorGradient[0].VecRGBA()
localColor[1] = p.ColorGradient[1].VecRGBA()
} else {
localColor[0] = p.Color.VecRGBA()
localColor[1] = localColor[0]
}
if p.Width == 1 {
// native GPU line (faster that emulating with rect)
if !p.NoCulling && !r.cullingLine(localPos) {
return
}
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeLine,
}
r.api.Draw(buildInShaderLine, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{
pos: localPos[0],
color: localColor[0],
},
{
pos: localPos[1],
color: localColor[1],
},
},
})
return
}
// not all GPU support of lines with width 1px+
// so, in case of custom width, we will emulate it with rect
angle := localPos[0].AngleTo(localPos[1])
offset := r.toLocalAspectRation(p.Width) / 2
topLeft := localPos[0].PolarOffset(offset, angle+(math.Pi/2))
bottomLeft := localPos[0].PolarOffset(offset, angle-(math.Pi/2))
topRight := localPos[1].PolarOffset(offset, angle+(math.Pi/2))
bottomRight := localPos[1].PolarOffset(offset, angle-(math.Pi/2))
rectPos := [4]glx.Vec2{topLeft, topRight, bottomRight, bottomLeft}
if !p.NoCulling && !r.cullingRect(rectPos) {
return
}
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeFill,
}
r.api.Draw(buildInShaderTriangle, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: rectPos[0], color: localColor[0]}, // tl
{pos: rectPos[1], color: localColor[1]}, // tr
{pos: rectPos[2], color: localColor[1]}, // br
},
})
r.api.Draw(buildInShaderTriangle, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: rectPos[2], color: localColor[1]}, // br
{pos: rectPos[3], color: localColor[0]}, // bl
{pos: rectPos[0], color: localColor[0]}, // tl
},
})
}
// -----------------------------------------------------------------------------
// Params2dTriangle is input for Draw2dTriangle
type Params2dTriangle struct {
Pos [3]glx.Vec2 // pixel position from top,left corner of surface in clock-wise order
Color glx.Color // color for all vertexes
ColorGradient [3]glx.Color // color for each vertex
ColorUseGradient bool // will use ColorGradient instead of Color
Filled bool // fill triangle with color/gradient
NoCulling bool // will send render command to GPU, even if all vertexes outside of visible screen
}
// Draw2dTriangle will draw triangle on current surface with current blend mode
// Params2dTriangle.Pos must be in clock-wise order
func (r *Render) Draw2dTriangle(p *Params2dTriangle) {
localPos := [3]glx.Vec2{
r.toLocalSpace2d(p.Pos[0]),
r.toLocalSpace2d(p.Pos[1]),
r.toLocalSpace2d(p.Pos[2]),
}
if !p.NoCulling && !r.cullingTriangle(localPos) {
return
}
localColor := [3]glx.Vec4{}
if p.ColorUseGradient {
localColor[0] = p.ColorGradient[0].VecRGBA()
localColor[1] = p.ColorGradient[1].VecRGBA()
localColor[2] = p.ColorGradient[2].VecRGBA()
} else {
localColor[0] = p.Color.VecRGBA()
localColor[1] = localColor[0]
localColor[2] = localColor[0]
}
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeLine,
}
if p.Filled {
mode.PolygonMode = vulkan.PolygonModeFill
}
r.api.Draw(buildInShaderTriangle, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: localPos[0], color: localColor[0]},
{pos: localPos[1], color: localColor[1]},
{pos: localPos[2], color: localColor[2]},
},
})
}
// -----------------------------------------------------------------------------
// Params2dRect is input for Draw2dRect
type Params2dRect struct {
Pos [4]glx.Vec2 // pixel position from top,left corner of surface in clock-wise order
Color glx.Color // color for all vertexes
ColorGradient [4]glx.Color // color for each vertex
ColorUseGradient bool // will use ColorGradient instead of Color
Filled bool // fill rect with color/gradient
NoCulling bool // will send render command to GPU, even if all vertexes outside of visible screen
}
// Draw2dRect will draw rect on current surface with current blend mode
// order of Params2dRect.Pos must be specified in order:
// 1) top-left
// 2) top-right
// 3) bottom-right
// 4) bottom-left
func (r *Render) Draw2dRect(p *Params2dRect) {
localPos := [4]glx.Vec2{
r.toLocalSpace2d(p.Pos[0]),
r.toLocalSpace2d(p.Pos[1]),
r.toLocalSpace2d(p.Pos[2]),
r.toLocalSpace2d(p.Pos[3]),
}
if !p.NoCulling && !r.cullingRect(localPos) {
return
}
localColor := [4]glx.Vec4{}
if p.ColorUseGradient {
localColor[0] = p.ColorGradient[0].VecRGBA()
localColor[1] = p.ColorGradient[1].VecRGBA()
localColor[2] = p.ColorGradient[2].VecRGBA()
localColor[3] = p.ColorGradient[3].VecRGBA()
} else {
localColor[0] = p.Color.VecRGBA()
localColor[1] = localColor[0]
localColor[2] = localColor[0]
localColor[3] = localColor[0]
}
if !p.Filled {
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeLine,
}
r.api.Draw(buildInShaderRect, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: localPos[0], color: localColor[0]},
{pos: localPos[1], color: localColor[1]},
{pos: localPos[2], color: localColor[2]},
{pos: localPos[3], color: localColor[3]},
},
})
return
}
// drawing two triangles faster, that outlined rect
// with custom polygon mode
// when rect is filled, two triangles visually looks same as rect
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeFill,
}
r.api.Draw(buildInShaderTriangle, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: localPos[0], color: localColor[0]}, // tl
{pos: localPos[1], color: localColor[1]}, // tr
{pos: localPos[2], color: localColor[2]}, // br
},
})
r.api.Draw(buildInShaderTriangle, mode, &shaderInputUniversal2d{
vertexes: []shaderInputUniversal2dVertex{
{pos: localPos[2], color: localColor[2]}, // br
{pos: localPos[3], color: localColor[3]}, // bl
{pos: localPos[0], color: localColor[0]}, // tl
},
})
}
// -----------------------------------------------------------------------------
// Params2dCircle is input for Draw2dCircle
type Params2dCircle struct {
Pos [4]glx.Vec2 // pixel position from top,left corner of surface in clock-wise order
PosCenter glx.Vec2 // position in pixels from top,left corner of surface
PosRadius float32 // radius in pixels
PosUseCenterRadius bool // will use PosCenter and PosRadius and ignore Pos (will be calculated)
HoleRadius float32 // value [0 .. 1]. 0=without hole, 0.1=90% circle is visible, 1=invisible circle
Smooth float32 // value [-1, 0 .. 1]. -1=no smooth, 0.005=default, 1=full blur (default value will be used, if no value (0) specified)
Color glx.Color // color for circle body/border
ColorGradient [4]glx.Color // color for circle part (tl, tr, br, bl)
ColorUseGradient bool // will use ColorGradient instead of Color
NoCulling bool // will send render command to GPU, even if all vertexes outside of visible screen
}
// Draw2dCircle will draw circle on current surface with current blend mode
func (r *Render) Draw2dCircle(p *Params2dCircle) {
if p.HoleRadius >= 0.9999 {
return
}
localPos := [4]glx.Vec2{}
if p.PosUseCenterRadius {
localPos[0] = r.toLocalSpace2d(p.PosCenter.Add(glx.Vec2{X: -p.PosRadius, Y: -p.PosRadius})) // tl
localPos[1] = r.toLocalSpace2d(p.PosCenter.Add(glx.Vec2{X: +p.PosRadius, Y: -p.PosRadius})) // tr
localPos[2] = r.toLocalSpace2d(p.PosCenter.Add(glx.Vec2{X: +p.PosRadius, Y: +p.PosRadius})) // br
localPos[3] = r.toLocalSpace2d(p.PosCenter.Add(glx.Vec2{X: -p.PosRadius, Y: +p.PosRadius})) // bl
} else {
localPos[0] = r.toLocalSpace2d(p.Pos[0])
localPos[1] = r.toLocalSpace2d(p.Pos[1])
localPos[2] = r.toLocalSpace2d(p.Pos[2])
localPos[3] = r.toLocalSpace2d(p.Pos[3])
}
if !p.NoCulling && !r.cullingRect(localPos) {
return
}
if p.Smooth == 0 {
// default value (if no specified)
p.Smooth = 0.005
}
if p.Smooth == -1 {
// specified to turn off
p.Smooth = 0
}
localColor := [4]glx.Vec4{}
if p.ColorUseGradient {
localColor[0] = p.ColorGradient[0].VecRGBA()
localColor[1] = p.ColorGradient[1].VecRGBA()
localColor[2] = p.ColorGradient[2].VecRGBA()
localColor[3] = p.ColorGradient[3].VecRGBA()
} else {
localColor[0] = p.Color.VecRGBA()
localColor[1] = localColor[0]
localColor[2] = localColor[0]
localColor[3] = localColor[0]
}
mode := vlk.DrawOptions{
PolygonMode: vulkan.PolygonModeFill,
}
r.api.Draw(buildInShaderCircle, mode, &shaderInputCircle2d{
vertexes: []shaderInputCircle2dVertex{
{pos: localPos[0], color: localColor[0]},
{pos: localPos[1], color: localColor[1]},
{pos: localPos[2], color: localColor[2]},
{pos: localPos[3], color: localColor[3]},
},
thickness: glx.Vec1{X: glx.Clamp(p.HoleRadius, 0, 1)},
smooth: glx.Vec1{X: glx.Clamp(p.Smooth, 0, 1)},
})
}