1 /* 2 Copyright (c) 2017-2018 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.graphics.shapes; 29 30 import std.math; 31 32 import dlib.core.memory; 33 import dlib.math.vector; 34 import dlib.container.array; 35 36 import dagon.core.libs; 37 import dagon.core.interfaces; 38 import dagon.core.ownership; 39 import dagon.graphics.mesh; 40 41 class ShapePlane: Mesh 42 { 43 this(float sx, float sz, uint numTiles, Owner owner) 44 { 45 super(owner); 46 47 float px = -sx * 0.5f; 48 float py = -sz * 0.5f; 49 50 float tileWidth = sx / numTiles; 51 float tileHeight = sz / numTiles; 52 53 Vector3f start = Vector3f(px, 0.0f, py); 54 55 uint gridSize = numTiles + 1; 56 57 vertices = New!(Vector3f[])(gridSize * gridSize); 58 normals = New!(Vector3f[])(gridSize * gridSize); 59 texcoords = New!(Vector2f[])(gridSize * gridSize); 60 61 for (uint i = 0, y = 0; y < gridSize; y++) 62 for (uint x = 0; x < gridSize; x++, i++) 63 { 64 vertices[i] = start + Vector3f(x * tileWidth, 0, y * tileHeight); 65 normals[i] = Vector3f(0, 1, 0); 66 texcoords[i] = Vector2f(x, y); 67 } 68 69 indices = New!(uint[3][])(gridSize * gridSize * 2); 70 71 uint index = 0; 72 for (uint y = 0; y < gridSize - 1; y++) 73 for (uint x = 0; x < gridSize - 1; x++) 74 { 75 uint offset = y * gridSize + x; 76 indices[index][2] = (offset + 0); 77 indices[index][1] = (offset + 1); 78 indices[index][0] = (offset + gridSize); 79 80 indices[index+1][2] = (offset + 1); 81 indices[index+1][1] = (offset + gridSize + 1); 82 indices[index+1][0] = (offset + gridSize); 83 84 index += 2; 85 } 86 87 dataReady = true; 88 prepareVAO(); 89 } 90 } 91 92 class ShapeQuad: Owner, Drawable 93 { 94 Vector2f[4] vertices; 95 Vector2f[4] texcoords; 96 uint[3][2] indices; 97 98 GLuint vao = 0; 99 GLuint vbo = 0; 100 GLuint tbo = 0; 101 GLuint eao = 0; 102 103 this(Owner o) 104 { 105 super(o); 106 107 vertices[0] = Vector2f(0, 1); 108 vertices[1] = Vector2f(0, 0); 109 vertices[2] = Vector2f(1, 0); 110 vertices[3] = Vector2f(1, 1); 111 112 texcoords[0] = Vector2f(0, 1); 113 texcoords[1] = Vector2f(0, 0); 114 texcoords[2] = Vector2f(1, 0); 115 texcoords[3] = Vector2f(1, 1); 116 117 indices[0][0] = 0; 118 indices[0][1] = 1; 119 indices[0][2] = 2; 120 121 indices[1][0] = 0; 122 indices[1][1] = 2; 123 indices[1][2] = 3; 124 125 glGenBuffers(1, &vbo); 126 glBindBuffer(GL_ARRAY_BUFFER, vbo); 127 glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof * 2, vertices.ptr, GL_STATIC_DRAW); 128 129 glGenBuffers(1, &tbo); 130 glBindBuffer(GL_ARRAY_BUFFER, tbo); 131 glBufferData(GL_ARRAY_BUFFER, texcoords.length * float.sizeof * 2, texcoords.ptr, GL_STATIC_DRAW); 132 133 glGenBuffers(1, &eao); 134 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 135 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length * uint.sizeof * 3, indices.ptr, GL_STATIC_DRAW); 136 137 glGenVertexArrays(1, &vao); 138 glBindVertexArray(vao); 139 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 140 141 glEnableVertexAttribArray(VertexAttrib.Vertices); 142 glBindBuffer(GL_ARRAY_BUFFER, vbo); 143 glVertexAttribPointer(VertexAttrib.Vertices, 2, GL_FLOAT, GL_FALSE, 0, null); 144 145 glEnableVertexAttribArray(VertexAttrib.Texcoords); 146 glBindBuffer(GL_ARRAY_BUFFER, tbo); 147 glVertexAttribPointer(VertexAttrib.Texcoords, 2, GL_FLOAT, GL_FALSE, 0, null); 148 149 glBindVertexArray(0); 150 } 151 152 ~this() 153 { 154 glDeleteVertexArrays(1, &vao); 155 glDeleteBuffers(1, &vbo); 156 glDeleteBuffers(1, &tbo); 157 glDeleteBuffers(1, &eao); 158 } 159 160 void update(double dt) 161 { 162 } 163 164 void render(RenderingContext* rc) 165 { 166 glDepthMask(0); 167 glBindVertexArray(vao); 168 glDrawElements(GL_TRIANGLES, cast(uint)indices.length * 3, GL_UNSIGNED_INT, cast(void*)0); 169 glBindVertexArray(0); 170 glDepthMask(1); 171 } 172 } 173 174 class ShapeBox: Mesh 175 { 176 this(Vector3f extents, Owner owner) 177 { 178 super(owner); 179 180 vertices = New!(Vector3f[])(24); 181 normals = New!(Vector3f[])(24); 182 texcoords = New!(Vector2f[])(24); 183 indices = New!(uint[3][])(12); 184 185 Vector3f pmax = +extents; 186 Vector3f pmin = -extents; 187 188 texcoords[0] = Vector2f(1, 0); normals[0] = Vector3f(0,0,1); vertices[0] = Vector3f(pmax.x, pmax.y, pmax.z); 189 texcoords[1] = Vector2f(0, 0); normals[1] = Vector3f(0,0,1); vertices[1] = Vector3f(pmin.x, pmax.y, pmax.z); 190 texcoords[2] = Vector2f(0, 1); normals[2] = Vector3f(0,0,1); vertices[2] = Vector3f(pmin.x, pmin.y, pmax.z); 191 texcoords[3] = Vector2f(1, 1); normals[3] = Vector3f(0,0,1); vertices[3] = Vector3f(pmax.x, pmin.y, pmax.z); 192 indices[0][0] = 0; indices[0][1] = 1; indices[0][2] = 2; 193 indices[1][0] = 2; indices[1][1] = 3; indices[1][2] = 0; 194 195 texcoords[4] = Vector2f(0, 0); normals[4] = Vector3f(1,0,0); vertices[4] = Vector3f(pmax.x, pmax.y, pmax.z); 196 texcoords[5] = Vector2f(0, 1); normals[5] = Vector3f(1,0,0); vertices[5] = Vector3f(pmax.x, pmin.y, pmax.z); 197 texcoords[6] = Vector2f(1, 1); normals[6] = Vector3f(1,0,0); vertices[6] = Vector3f(pmax.x, pmin.y, pmin.z); 198 texcoords[7] = Vector2f(1, 0); normals[7] = Vector3f(1,0,0); vertices[7] = Vector3f(pmax.x, pmax.y, pmin.z); 199 indices[2][0] = 4; indices[2][1] = 5; indices[2][2] = 6; 200 indices[3][0] = 6; indices[3][1] = 7; indices[3][2] = 4; 201 202 texcoords[8] = Vector2f(1, 1); normals[8] = Vector3f(0,1,0); vertices[8] = Vector3f(pmax.x, pmax.y, pmax.z); 203 texcoords[9] = Vector2f(1, 0); normals[9] = Vector3f(0,1,0); vertices[9] = Vector3f(pmax.x, pmax.y, pmin.z); 204 texcoords[10] = Vector2f(0, 0); normals[10] = Vector3f(0,1,0); vertices[10] = Vector3f(pmin.x, pmax.y, pmin.z); 205 texcoords[11] = Vector2f(0, 1); normals[11] = Vector3f(0,1,0); vertices[11] = Vector3f(pmin.x, pmax.y, pmax.z); 206 indices[4][0] = 8; indices[4][1] = 9; indices[4][2] = 10; 207 indices[5][0] = 10; indices[5][1] = 11; indices[5][2] = 8; 208 209 texcoords[12] = Vector2f(1, 0); normals[12] = Vector3f(-1,0,0); vertices[12] = Vector3f(pmin.x, pmax.y, pmax.z); 210 texcoords[13] = Vector2f(0, 0); normals[13] = Vector3f(-1,0,0); vertices[13] = Vector3f(pmin.x, pmax.y, pmin.z); 211 texcoords[14] = Vector2f(0, 1); normals[14] = Vector3f(-1,0,0); vertices[14] = Vector3f(pmin.x, pmin.y, pmin.z); 212 texcoords[15] = Vector2f(1, 1); normals[15] = Vector3f(-1,0,0); vertices[15] = Vector3f(pmin.x, pmin.y, pmax.z); 213 indices[6][0] = 12; indices[6][1] = 13; indices[6][2] = 14; 214 indices[7][0] = 14; indices[7][1] = 15; indices[7][2] = 12; 215 216 texcoords[16] = Vector2f(0, 1); normals[16] = Vector3f(0,-1,0); vertices[16] = Vector3f(pmin.x, pmin.y, pmin.z); 217 texcoords[17] = Vector2f(1, 1); normals[17] = Vector3f(0,-1,0); vertices[17] = Vector3f(pmax.x, pmin.y, pmin.z); 218 texcoords[18] = Vector2f(1, 0); normals[18] = Vector3f(0,-1,0); vertices[18] = Vector3f(pmax.x, pmin.y, pmax.z); 219 texcoords[19] = Vector2f(0, 0); normals[19] = Vector3f(0,-1,0); vertices[19] = Vector3f(pmin.x, pmin.y, pmax.z); 220 indices[8][0] = 16; indices[8][1] = 17; indices[8][2] = 18; 221 indices[9][0] = 18; indices[9][1] = 19; indices[9][2] = 16; 222 223 texcoords[20] = Vector2f(0, 1); normals[20] = Vector3f(0,0,-1); vertices[20] = Vector3f(pmax.x, pmin.y, pmin.z); 224 texcoords[21] = Vector2f(1, 1); normals[21] = Vector3f(0,0,-1); vertices[21] = Vector3f(pmin.x, pmin.y, pmin.z); 225 texcoords[22] = Vector2f(1, 0); normals[22] = Vector3f(0,0,-1); vertices[22] = Vector3f(pmin.x, pmax.y, pmin.z); 226 texcoords[23] = Vector2f(0, 0); normals[23] = Vector3f(0,0,-1); vertices[23] = Vector3f(pmax.x, pmax.y, pmin.z); 227 indices[10][0] = 20; indices[10][1] = 21; indices[10][2] = 22; 228 indices[11][0] = 22; indices[11][1] = 23; indices[11][2] = 20; 229 230 dataReady = true; 231 prepareVAO(); 232 } 233 } 234 235 enum PI2 = PI * 2.0f; 236 enum HALF_PI = PI * 0.5f; 237 238 Vector2f envMapEquirect(Vector3f dir) 239 { 240 //float phi = acos(dir.y); 241 //float theta = atan2(dir.x, dir.z) + PI; 242 //return Vector2f(theta / PI2, phi / PI); 243 Vector2f uv; 244 uv.y = acos(dir.y) / PI; 245 uv.x = (PI + atan2(dir.x, dir.z)) / PI2; 246 return uv; 247 } 248 249 class ShapeSphere: Mesh 250 { 251 DynamicArray!Vector3f daVertices; 252 DynamicArray!Vector3f daNormals; 253 DynamicArray!Vector2f daTexcoords; 254 DynamicArray!(uint[3]) daIndices; 255 256 this(float radius, int slices, int stacks, bool invNormals, Owner o) 257 { 258 super(o); 259 260 float X1, Y1, X2, Y2, Z1, Z2; 261 float inc1, inc2, inc3, inc4, inc5, radius1, radius2; 262 uint[3] tri; 263 uint i = 0; 264 265 float cuts = stacks; 266 float invCuts = 1.0f / cuts; 267 float heightStep = 2.0f * invCuts; 268 269 float invSlices = 1.0f / slices; 270 float angleStep = (2.0f * PI) * invSlices; 271 272 for(int h = 0; h < stacks; h++) 273 { 274 float h1Norm = cast(float)h * invCuts * 2.0f - 1.0f; 275 float h2Norm = cast(float)(h+1) * invCuts * 2.0f - 1.0f; 276 float y1 = sin(HALF_PI * h1Norm); 277 float y2 = sin(HALF_PI * h2Norm); 278 279 float circleRadius1 = cos(HALF_PI * y1); 280 float circleRadius2 = cos(HALF_PI * y2); 281 282 for(int a = 0; a < slices; a++) 283 { 284 float x1a = sin(angleStep * a) * circleRadius1; 285 float z1a = cos(angleStep * a) * circleRadius1; 286 float x2a = sin(angleStep * (a + 1)) * circleRadius1; 287 float z2a = cos(angleStep * (a + 1)) * circleRadius1; 288 289 float x1b = sin(angleStep * a) * circleRadius2; 290 float z1b = cos(angleStep * a) * circleRadius2; 291 float x2b = sin(angleStep * (a + 1)) * circleRadius2; 292 float z2b = cos(angleStep * (a + 1)) * circleRadius2; 293 294 Vector3f v1 = Vector3f(x1a, y1, z1a); 295 Vector3f v2 = Vector3f(x2a, y1, z2a); 296 Vector3f v3 = Vector3f(x1b, y2, z1b); 297 Vector3f v4 = Vector3f(x2b, y2, z2b); 298 299 Vector3f n1 = v1.normalized; 300 Vector3f n2 = v2.normalized; 301 Vector3f n3 = v3.normalized; 302 Vector3f n4 = v4.normalized; 303 304 daVertices.append(n1 * radius); 305 daVertices.append(n2 * radius); 306 daVertices.append(n3 * radius); 307 308 daVertices.append(n3 * radius); 309 daVertices.append(n2 * radius); 310 daVertices.append(n4 * radius); 311 312 float sign = invNormals? -1.0f : 1.0f; 313 314 daNormals.append(n1 * sign); 315 daNormals.append(n2 * sign); 316 daNormals.append(n3 * sign); 317 318 daNormals.append(n3 * sign); 319 daNormals.append(n2 * sign); 320 daNormals.append(n4 * sign); 321 322 auto uv1 = Vector2f(0, 1); 323 auto uv2 = Vector2f(1, 1); 324 auto uv3 = Vector2f(0, 0); 325 auto uv4 = Vector2f(1, 0); 326 327 daTexcoords.append(uv1); 328 daTexcoords.append(uv2); 329 daTexcoords.append(uv3); 330 331 daTexcoords.append(uv3); 332 daTexcoords.append(uv2); 333 daTexcoords.append(uv4); 334 335 if (invNormals) 336 { 337 tri[0] = i+2; 338 tri[1] = i+1; 339 tri[2] = i; 340 daIndices.append(tri); 341 342 tri[0] = i+5; 343 tri[1] = i+4; 344 tri[2] = i+3; 345 daIndices.append(tri); 346 } 347 else 348 { 349 tri[0] = i; 350 tri[1] = i+1; 351 tri[2] = i+2; 352 daIndices.append(tri); 353 354 tri[0] = i+3; 355 tri[1] = i+4; 356 tri[2] = i+5; 357 daIndices.append(tri); 358 } 359 360 i += 6; 361 } 362 } 363 364 /* 365 for(int w = 0; w < resolution; w++) 366 { 367 368 369 for(int h = (-resolution/2); h < (resolution/2); h++) 370 { 371 inc1 = (w/cast(float)resolution)*2*PI; 372 inc2 = ((w+1)/cast(float)resolution)*2*PI; 373 374 inc3 = (h/cast(float)resolution)*PI; 375 inc4 = ((h+1)/cast(float)resolution)*PI; 376 377 X1 = sin(inc1); 378 Y1 = cos(inc1); 379 X2 = sin(inc2); 380 Y2 = cos(inc2); 381 382 radius1 = radius*cos(inc3); 383 radius2 = radius*cos(inc4); 384 385 Z1 = radius*sin(inc3); 386 Z2 = radius*sin(inc4); 387 388 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 389 daVertices.append(Vector3f(radius1*X2,Z1,radius1*Y2)); 390 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 391 392 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 393 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 394 daVertices.append(Vector3f(radius2*X1,Z2,radius2*Y1)); 395 396 auto uv1 = Vector2f(0, 0); 397 auto uv2 = Vector2f(0, 1); 398 auto uv3 = Vector2f(1, 1); 399 auto uv4 = Vector2f(1, 0); 400 401 daTexcoords.append(uv1); 402 daTexcoords.append(uv2); 403 daTexcoords.append(uv3); 404 405 daTexcoords.append(uv1); 406 daTexcoords.append(uv3); 407 daTexcoords.append(uv4); 408 409 float sign = invNormals? -1.0f : 1.0f; 410 411 auto n1 = Vector3f(X1,Z1,Y1).normalized; 412 auto n2 = Vector3f(X2,Z1,Y2).normalized; 413 auto n3 = Vector3f(X2,Z2,Y2).normalized; 414 auto n4 = Vector3f(X1,Z2,Y1).normalized; 415 416 daNormals.append(n1 * sign); 417 daNormals.append(n2 * sign); 418 daNormals.append(n3 * sign); 419 420 daNormals.append(n1 * sign); 421 daNormals.append(n3 * sign); 422 daNormals.append(n4 * sign); 423 424 if (invNormals) 425 { 426 tri[0] = i+2; 427 tri[1] = i+1; 428 tri[2] = i; 429 daIndices.append(tri); 430 431 tri[0] = i+5; 432 tri[1] = i+4; 433 tri[2] = i+3; 434 daIndices.append(tri); 435 } 436 else 437 { 438 tri[0] = i; 439 tri[1] = i+1; 440 tri[2] = i+2; 441 daIndices.append(tri); 442 443 tri[0] = i+3; 444 tri[1] = i+4; 445 tri[2] = i+5; 446 daIndices.append(tri); 447 } 448 449 i += 6; 450 } 451 } 452 */ 453 454 vertices = New!(Vector3f[])(daVertices.length); 455 vertices[] = daVertices.data[]; 456 457 normals = New!(Vector3f[])(daNormals.length); 458 normals[] = daNormals.data[]; 459 460 texcoords = New!(Vector2f[])(daTexcoords.length); 461 texcoords[] = daTexcoords.data[]; 462 463 indices = New!(uint[3][])(daIndices.length); 464 indices[] = daIndices.data[]; 465 466 daVertices.free(); 467 daNormals.free(); 468 daTexcoords.free(); 469 daIndices.free(); 470 471 dataReady = true; 472 prepareVAO(); 473 } 474 } 475 476 // TODO: other shapes from original Dagon