-
Notifications
You must be signed in to change notification settings - Fork 0
/
prims.nim
166 lines (149 loc) · 5.38 KB
/
prims.nim
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
import vecmath
import math
import unsigned
import algorithm
import sequtils
import colors
import ecs
type TPrimMesh* = object
verts*: seq[TVec3f]
indices*: seq[uint32]
type TPrim* = object
transform*: TMat4f
color*: TVec3f
mesh*: TPrimMesh
type TPrimPoint* = object
pos*: TVec3f
color*: TVec3f
MakeEntityComponent(TPrim)
proc PrimCircleMesh(radius: float): TPrimMesh =
const steps = 8
var nextVert = vec3f(radius,0,0)
var rotation = quatFromAngleAxis((2*PI)/steps, vec3f(0,1,0))
result.verts = @[]
result.indices = @[]
result.verts.add(vec3f(0,0,0))
result.indices.add(0)
for i in 1..steps:
nextVert = mulv(rotation, nextVert)
result.verts.add(nextVert)
result.indices.add(result.verts.high.uint32)
result.indices.add(result.verts.high.uint32-1)
result.indices.add(0)
result.indices.add(1)
result.indices.add(result.verts.high.uint32)
proc PrimConeMesh*(radius: float, height: float): TPrimMesh =
const steps = 8
result = PrimCircleMesh(radius)
result.verts.add(vec3f(0,height,0))
var topIdx = result.verts.high
for i in 1..steps:
result.indices.add(uint32(i))
result.indices.add(uint32(i+1))
result.indices.add(topIdx.uint32)
result.indices.add(result.verts.high.uint32 - 1)
result.indices.add(1)
result.indices.add(topIdx.uint32)
proc PrimCylinderMesh*(radius: float, height: float): TPrimMesh =
result = PrimCircleMesh(radius)
for i,elm in result.verts.pairs():
result.verts[i][2] = result.verts[i][2] - height/2
var topCircle = PrimCircleMesh(radius)
topCircle.indices.reverse()
for i,elm in topCircle.verts.pairs():
topCircle.verts[i][2] = topCircle.verts[i][2] + height/2
for i,elm in topCircle.indices.pairs():
topCircle.indices[i] = topCircle.indices[i] + topCircle.verts.len.uint32
#original length of the first circle, so we can iterate
#and add the sides
var circleLen = result.verts.len.uint32
result.verts = concat(result.verts, topCircle.verts)
result.indices = concat(result.indices, topCircle.indices)
for i in 1..circleLen - 2:
result.indices.add(uint32(i+1))
result.indices.add(uint32(i + circleLen))
result.indices.add(uint32(i))
result.indices.add(uint32(i + circleLen))
result.indices.add(uint32(i+1))
result.indices.add(uint32(i + circleLen + 1))
result.indices.add(1)
result.indices.add(circleLen + 1)
result.indices.add(circleLen - 1)
result.indices.add(circleLen + 1)
result.indices.add(uint32(result.verts.high))
result.indices.add(circleLen - 1)
proc PrimBoundingBoxMesh(aabb: TAlignedBox3f): TPrimMesh =
result.verts = @[]
result.indices = @[]
for elm in TCornerType:
var corner = aabb.corner(elm)
result.verts.add(corner)
result.indices = @[
0.uint32,5,4,
1,5,0,
0,2,1,
1,2,3,
1,7,5,
3,7,1,
3,6,7,
2,6,3,
0,6,2,
4,6,0,
5,6,4,
7,6,5
]
proc initPrim(mesh: TPrimMesh, color: TColor, pos: TVec3f): TPrim =
result.mesh = mesh
var (r,g,b) = extractRGB(color)
result.color = vec3f(float(r),float(g),float(b)).normalize()
result.transform = toTranslationMatrix(pos)
proc PrimCone*(pos: TVec3f = vec3f(0,0,0),
color: TColor = colForestGreen,
radius: float = 10.0,
height: float = 10.0): TPrim =
result = initPrim(PrimConeMesh(radius, height), color, pos)
proc PrimCylinder*(pos: TVec3f = vec3f(0,0,0),
color: TColor = colBlue,
radius: float = 10.0,
height: float = 10.0): TPrim =
result = initPrim(PrimCylinderMesh(radius, height), color, pos)
proc PrimHandle*(pos: TVec3f = vec3f(0,0,0),
scale: float = 1.0): seq[TPrim] =
let height = 4.0 * scale
# we translate before we rotate, so we only need
# the translation in the 'y' axis
let transl = vec3f(0,height/2,0)
var xcyl = PrimCylinder(pos, colRed, 1.0 * scale, height)
var ycyl = PrimCylinder(pos, colGreen, 1.0 * scale, height)
var zcyl = PrimCylinder(pos, colBlue, 1.0 * scale, height)
let xrot = quatFromAngleAxis(PI/2, vec3f(0,0,1))
let yrot = identityQuatf()
let zrot = quatFromAngleAxis(PI/2, vec3f(1,0,0))
proc moveCyl(rot: TQuatf, cyl: var TPrimMesh) =
for i,v in cyl.verts:
cyl.verts[i] = v + transl
cyl.verts[i] = mulv(rot, v)
moveCyl(xrot, xcyl.mesh)
moveCyl(yrot, ycyl.mesh)
moveCyl(zrot, zcyl.mesh)
result = @[xcyl, ycyl, zcyl]
proc PrimBoundingBox*(aabb: TAlignedBox3f): TPrim =
result = initPrim(PrimBoundingBoxMesh(aabb), colGreen, vec3f(0,0,0))
## what follows is the immediate mode primitive stack it works in concert with the ECS system
## each of the following functions will add a primitive to a special RenderingStack list that is cleared
## after it is rendered, thus we get a kind of immediate mode rendering.
type TPrimitiveStack* = seq[TPrim]
MakeEntityComponent(TPrimitiveStack)
proc DrawPrim*(scene: SceneId, prim: TPrim) =
if components(scene, TPrimitiveStack).len == 0:
var stack: TPrimitiveStack = @[]
scene.add(stack)
var stack = scene?TPrimitiveStack
stack[].add(prim)
proc DrawPrim*(prim: TPrim) = DrawPrim(0.SceneId, prim)
proc DrawPrimBoundingBox*(scene: SceneId, aabb: TAlignedBox3f) =
DrawPrim(scene, PrimBoundingBox(aabb))
proc DrawPrimCone*(scene: SceneId, pos: TVec3f) =
DrawPrim(scene, PrimCone(pos))
proc DrawPrimBoundingBox*(aabb: TAlignedBox3f) = DrawPrimBoundingBox(0.SceneId, aabb)
proc DrawPrimCone*(pos: TVec3f) = DrawPrimCone(0.SceneId, pos)