1 /++ 2 The module for generating vertices for drawing open graphics by the library. 3 4 By means of $(HREF shape.html, Shape)'s, you can generate its vertices for a convenient 5 representation and transfer such vertices to the shader to draw 6 the corresponding shapes. 7 8 Macros: 9 LREF = <a href="#$1">$1</a> 10 HREF = <a href="$1">$2</a> 11 12 Authors: $(HREF https://github.com/TodNaz,TodNaz) 13 Copyright: Copyright (c) 2020 - 2021, TodNaz. 14 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 15 +/ 16 module tida.vertgen; 17 18 import tida.shape; 19 import tida.vector; 20 import std.traits; 21 import tida.color; 22 23 template glType(T) 24 { 25 import tida.gl; 26 27 static if (is(T : float)) 28 enum glType = GL_FLOAT; 29 else 30 static if (is(T : double)) 31 enum glType = GL_DOUBLE; 32 else 33 static if (is(T : byte)) 34 enum glType = GL_BYTE; 35 else 36 static if (is(T : ubyte)) 37 enum glType = GL_UNSIGNED_BYTE; 38 else 39 static if (is(T : int)) 40 enum glType = GL_INT; 41 else 42 static if (is(T : uint)) 43 enum glType = GL_UNSIGNED_INT; 44 } 45 46 /++ 47 A storage object for the identifiers of the buffers stored in memory. 48 +/ 49 class VertexInfo(T) 50 if (isNumeric!T) 51 { 52 import tida.gl; 53 import tida.shape; 54 55 private: 56 uint bid; 57 uint vid; 58 uint eid; 59 60 size_t blength; 61 size_t elength; 62 63 public: 64 Shape!T shapeinfo; /// Shape information 65 66 @trusted: 67 /++ 68 Enters data into a separate memory. 69 70 Params: 71 buffer = Binded buffer. 72 +/ 73 void bindFromBuffer(T[] buffer) 74 { 75 glGenVertexArrays(1, &vid); 76 glGenBuffers(1, &bid); 77 glBindVertexArray(vid); 78 79 glBindBuffer(GL_ARRAY_BUFFER, bid); 80 glBufferData(GL_ARRAY_BUFFER, T.sizeof * buffer.length, buffer.ptr, GL_STATIC_DRAW); 81 82 glBindBuffer(GL_ARRAY_BUFFER, 0); 83 glBindVertexArray(0); 84 85 blength = buffer.length; 86 } 87 88 /++ 89 Enters data into a separate memory. 90 91 Params: 92 buffer = Binded buffer. 93 element = Binded element buffer. 94 +/ 95 void bindFromBufferAndElem(T[] buffer, uint[] element) 96 { 97 glGenVertexArrays(1, &vid); 98 glGenBuffers(1, &bid); 99 glBindVertexArray(vid); 100 101 glBindBuffer(GL_ARRAY_BUFFER, bid); 102 glBufferData(GL_ARRAY_BUFFER, T.sizeof * buffer.length, buffer.ptr, GL_STATIC_DRAW); 103 104 glGenBuffers(1, &eid); 105 106 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eid); 107 glBufferData(GL_ELEMENT_ARRAY_BUFFER, uint.sizeof * buffer.length, element.ptr, GL_STATIC_DRAW); 108 109 glBindBuffer(GL_ARRAY_BUFFER, 0); 110 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 111 glBindVertexArray(0); 112 113 blength = buffer.length; 114 elength = element.length; 115 } 116 117 /// Binds an array of vertices to the current render cycle. 118 void bindVertexArray() nothrow 119 { 120 glBindVertexArray(vid); 121 } 122 123 /// Binds an buffer of vertices to the current render cycle. 124 void bindBuffer() nothrow 125 { 126 glBindBuffer(GL_ARRAY_BUFFER, bid); 127 } 128 129 /// Binds an element buffer of vertices to the current render cycle. 130 void bindElementBuffer() nothrow 131 { 132 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eid); 133 } 134 135 /// Unbinds an buffer of vertices to the current render cycle. 136 static void unbindBuffer() nothrow 137 { 138 glBindBuffer(GL_ARRAY_BUFFER, 0); 139 } 140 141 /// Unbinds an element buffer of vertices to the current render cycle. 142 static void unbindElementBuffer() nothrow 143 { 144 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 145 } 146 147 /// Unbinds an array of vertices to the current render cycle. 148 static void unbindVertexArray() nothrow 149 { 150 glBindVertexArray(0); 151 } 152 153 /// Define an array of generic vertex attribute data 154 void vertexAttribPointer(uint vertLocation, int sample = 2) nothrow 155 { 156 glVertexAttribPointer(vertLocation, 2, glType!T, false, sample * cast(int) T.sizeof, null); 157 } 158 159 /// Define an array of generic vertex attribute data 160 void textureAttribPointer(uint location, int sample = 4) nothrow 161 { 162 glVertexAttribPointer(location, 2, glType!T, false, sample * cast(int) T.sizeof, cast(void*) (T.sizeof * 2)); 163 } 164 165 /// Define an array of generic vertex attribute data 166 void colorAttribPointer(uint location, uint sample = 6) nothrow 167 { 168 glVertexAttribPointer(location, 4, glType!T, false, sample * cast(int) T.sizeof, cast(void*) (T.sizeof * 2)); 169 } 170 171 /// ID of the generated vertex array. 172 @property uint idVertexArray() nothrow inout 173 { 174 return vid; 175 } 176 177 /// The identifier of the buffer in memory. 178 @property uint idBufferArray() nothrow inout 179 { 180 return bid; 181 } 182 183 /// The identifier of the elements in memory. 184 @property uint idElementArray() nothrow inout 185 { 186 return eid; 187 } 188 189 /// Buffer length. 190 @property size_t length() nothrow inout 191 { 192 return blength; 193 } 194 195 /// Element length 196 @property size_t elementLength() nothrow inout 197 { 198 return elength; 199 } 200 201 /++ 202 Outputs the rendering of the buffer. 203 204 Params: 205 type = Shape type 206 count = Count rendering shapes 207 +/ 208 void draw(ShapeType type, int count = 1) 209 { 210 switch(type) 211 { 212 case ShapeType.line: 213 glDrawArrays(GL_LINES, 0, 2 * count); 214 break; 215 216 case ShapeType.rectangle: 217 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, null); 218 break; 219 220 case ShapeType.roundrect: 221 glDrawArrays(GL_TRIANGLES, 0, cast(uint) (blength / 2 * count)); 222 break; 223 224 case ShapeType.circle: 225 glDrawArrays(GL_TRIANGLE_FAN, 0, cast(uint) (blength / 4 * count)); 226 break; 227 228 case ShapeType.triangle: 229 glDrawArrays(GL_TRIANGLES, 0, cast(uint) blength); 230 break; 231 232 case ShapeType.polygon: 233 glDrawArrays(GL_TRIANGLE_FAN, 0, cast(uint) blength); 234 break; 235 236 default: 237 assert(null, "Unknown type!"); 238 } 239 } 240 241 /// Destroys vertex information. 242 void deleting() 243 { 244 if(idBufferArray != 0) glDeleteBuffers(1, &bid); 245 if(idVertexArray != 0) glDeleteVertexArrays(1, &vid); 246 if(idElementArray != 0) glDeleteBuffers(1, &eid); 247 248 bid = 0; 249 vid = 0; 250 eid = 0; 251 } 252 253 ~this() 254 { 255 this.deleting(); 256 } 257 } 258 259 /++ 260 Generates the vertices of shapes to be rendered using hardware acceleration. 261 262 Params: 263 T = Type. 264 shape = Shape information. 265 textureSize = Texture size. If not specified, will not generate texture 266 vertices for vertices. 267 +/ 268 Vector!T[] generateBuffer(T)(Shape!T shape, Vector!T textureSize = vecNaN!T) @safe nothrow pure 269 { 270 import std.math : cos, sin; 271 272 Vector!T[] vertexs; 273 274 switch (shape.type) 275 { 276 case ShapeType.point: 277 vertexs = [shape.begin]; 278 break; 279 280 case ShapeType.line: 281 vertexs = [shape.begin, shape.end]; 282 break; 283 284 case ShapeType.rectangle: 285 vertexs = [ 286 vec!T(shape.end.x, shape.begin.y), 287 shape.end, 288 vec!T(shape.begin.x, shape.end.y), 289 shape.begin 290 ]; 291 break; 292 293 case ShapeType.roundrect: 294 immutable pos1 = shape.begin + vec!T(shape.radius, 0); 295 immutable pos2 = shape.begin + vec!T(0, shape.radius); 296 297 immutable size = vec!T(shape.width, shape.height); 298 299 vertexs = [ 300 // FIRST RECTANGLE 301 pos1, 302 pos1 + vec!T(size.x - shape.radius * 2, 0), 303 pos1 + size - vec!T(shape.radius * 2, 0), 304 305 pos1, 306 pos1 + vec!T(0, size.y), 307 pos1 + size - vec!T(shape.radius * 2, 0), 308 309 // SECOND RECTANGLE 310 pos2, 311 pos2 + vec!T(size.x, 0), 312 pos2 + size - vec!T(0, shape.radius * 2), 313 314 pos2, 315 pos2 + vec!T(0, size.y - shape.radius * 2), 316 pos2 + size - vec!T(0, shape.radius * 2) 317 ]; 318 319 void rounded(vec!T pos, T a1, T a2, T iter) 320 { 321 for (T i = a1; i <= a2;) 322 { 323 vertexs ~= pos + vec!T(cos(i), sin(i)) * shape.radius; 324 325 i += iter; 326 vertexs ~= pos + vec!T(cos(i), sin(i)) * shape.radius; 327 vertexs ~= pos; 328 329 i += iter; 330 } 331 } 332 333 rounded(shape.begin + vec!T(shape.radius, shape.radius), 270, 360, 0.25); 334 rounded(shape.begin + vec!T(size.x - shape.radius, shape.radius), 0, 90, 0.25); 335 rounded(shape.begin + vec!T(shape.radius, size.y - shape.radius), 180, 270, 0.25); 336 rounded(shape.begin + vec!T(size.x - shape.radius, size.y - shape.radius), 90, 180, 0.25); 337 break; 338 339 case ShapeType.circle: 340 for (T i = 0; i <= 360;) 341 { 342 vertexs ~= shape.begin + vec!T(cos(i), sin(i)) * shape.radius; 343 344 i += 0.25; 345 vertexs ~= shape.begin + vec!T(cos(i), sin(i)) * shape.radius; 346 vertexs ~= shape.begin; 347 348 i += 0.25; 349 } 350 break; 351 352 case ShapeType.triangle: 353 vertexs = shape.vertexs; 354 break; 355 356 case ShapeType.polygon: 357 vertexs = shape.data; 358 vertexs ~= shape.data[0]; 359 break; 360 361 case ShapeType.multi: 362 foreach (cs; shape.shapes) 363 { 364 vertexs ~= generateBuffer!T(cs); 365 } 366 break; 367 368 default: 369 return null; 370 } 371 372 if (!isVectorNaN!T(textureSize)) 373 { 374 auto vertDump = vertexs.dup; 375 vertexs.length = 0; 376 377 const clip = rectVertexs!T(vertDump); 378 379 foreach (e; vertDump) { 380 vertexs ~= [e, 381 vec!T ((e.x - clip.x) / clip.width, 382 (e.y - clip.y) / clip.height)]; 383 } 384 } 385 386 return vertexs; 387 } 388 389 /// ditto 390 VertexInfo!T generateVertex(T)(Shape!T shape, Vector!T textSize = vecNaN!T) @trusted 391 { 392 T[] buffer; 393 394 buffer = generateBuffer!T(shape, textSize).generateArray; 395 396 VertexInfo!T info = new VertexInfo!T(); 397 398 if (shape.type == ShapeType.rectangle) 399 { 400 uint[] elements = [0 ,1, 2, 2, 3 ,0]; 401 info.bindFromBufferAndElem(buffer, elements); 402 }else 403 { 404 info.bindFromBuffer(buffer); 405 } 406 407 info.shapeinfo = shape; 408 409 destroy(buffer); 410 411 return info; 412 } 413 414 /// ditto 415 VertexInfo!T generateVertexColor(T)(Shape!T shape, Color!ubyte[] colors) @trusted 416 { 417 T[] buffer; 418 Color!float[] fcolors; 419 420 foreach (e; colors) 421 fcolors ~= e.convert!(ubyte, float); 422 423 buffer = generateBuffer!T(shape).generateArray; 424 T[] buffDump = buffer.dup; 425 buffer = []; 426 427 VertexInfo!T info = new VertexInfo!T(); 428 429 size_t j = 0; 430 for (size_t i = 0; i < buffDump.length; i += 2) 431 { 432 buffer ~= buffDump[i .. i + 2] ~ fcolors[j].toBytes!(PixelFormat.RGBA); 433 j++; 434 } 435 436 if (shape.type == ShapeType.rectangle) 437 { 438 uint[] elements = [0 ,1, 2, 2, 3 ,0]; 439 info.bindFromBufferAndElem(buffer, elements); 440 }else 441 { 442 info.bindFromBuffer(buffer); 443 } 444 445 info.shapeinfo = shape; 446 447 destroy(buffer); 448 449 return info; 450 }