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(0); 142 glBindBuffer(GL_ARRAY_BUFFER, vbo); 143 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null); 144 145 glEnableVertexAttribArray(1); 146 glBindBuffer(GL_ARRAY_BUFFER, tbo); 147 glVertexAttribPointer(1, 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 enum PI2 = PI * 2.0f; 175 enum HALF_PI = PI * 0.5f; 176 177 Vector2f envMapEquirect(Vector3f dir) 178 { 179 //float phi = acos(dir.y); 180 //float theta = atan2(dir.x, dir.z) + PI; 181 //return Vector2f(theta / PI2, phi / PI); 182 Vector2f uv; 183 uv.y = acos(dir.y) / PI; 184 uv.x = (PI + atan2(dir.x, dir.z)) / PI2; 185 return uv; 186 } 187 188 class ShapeSphere: Mesh 189 { 190 DynamicArray!Vector3f daVertices; 191 DynamicArray!Vector3f daNormals; 192 DynamicArray!Vector2f daTexcoords; 193 DynamicArray!(uint[3]) daIndices; 194 195 this(float radius, int slices, int stacks, bool invNormals, Owner o) 196 { 197 super(o); 198 199 float X1, Y1, X2, Y2, Z1, Z2; 200 float inc1, inc2, inc3, inc4, inc5, radius1, radius2; 201 uint[3] tri; 202 uint i = 0; 203 204 float cuts = stacks; 205 float invCuts = 1.0f / cuts; 206 float heightStep = 2.0f * invCuts; 207 208 float invSlices = 1.0f / slices; 209 float angleStep = (2.0f * PI) * invSlices; 210 211 for(int h = 0; h < stacks; h++) 212 { 213 float h1Norm = cast(float)h * invCuts * 2.0f - 1.0f; 214 float h2Norm = cast(float)(h+1) * invCuts * 2.0f - 1.0f; 215 float y1 = sin(HALF_PI * h1Norm); 216 float y2 = sin(HALF_PI * h2Norm); 217 218 float circleRadius1 = cos(HALF_PI * y1); 219 float circleRadius2 = cos(HALF_PI * y2); 220 221 for(int a = 0; a < slices; a++) 222 { 223 float x1a = sin(angleStep * a) * circleRadius1; 224 float z1a = cos(angleStep * a) * circleRadius1; 225 float x2a = sin(angleStep * (a + 1)) * circleRadius1; 226 float z2a = cos(angleStep * (a + 1)) * circleRadius1; 227 228 float x1b = sin(angleStep * a) * circleRadius2; 229 float z1b = cos(angleStep * a) * circleRadius2; 230 float x2b = sin(angleStep * (a + 1)) * circleRadius2; 231 float z2b = cos(angleStep * (a + 1)) * circleRadius2; 232 233 Vector3f v1 = Vector3f(x1a, y1, z1a); 234 Vector3f v2 = Vector3f(x2a, y1, z2a); 235 Vector3f v3 = Vector3f(x1b, y2, z1b); 236 Vector3f v4 = Vector3f(x2b, y2, z2b); 237 238 Vector3f n1 = v1.normalized; 239 Vector3f n2 = v2.normalized; 240 Vector3f n3 = v3.normalized; 241 Vector3f n4 = v4.normalized; 242 243 daVertices.append(n1 * radius); 244 daVertices.append(n2 * radius); 245 daVertices.append(n3 * radius); 246 247 daVertices.append(n3 * radius); 248 daVertices.append(n2 * radius); 249 daVertices.append(n4 * radius); 250 251 float sign = invNormals? -1.0f : 1.0f; 252 253 daNormals.append(n1 * sign); 254 daNormals.append(n2 * sign); 255 daNormals.append(n3 * sign); 256 257 daNormals.append(n3 * sign); 258 daNormals.append(n2 * sign); 259 daNormals.append(n4 * sign); 260 261 auto uv1 = Vector2f(0, 1); 262 auto uv2 = Vector2f(1, 1); 263 auto uv3 = Vector2f(0, 0); 264 auto uv4 = Vector2f(1, 0); 265 266 daTexcoords.append(uv1); 267 daTexcoords.append(uv2); 268 daTexcoords.append(uv3); 269 270 daTexcoords.append(uv3); 271 daTexcoords.append(uv2); 272 daTexcoords.append(uv4); 273 274 if (invNormals) 275 { 276 tri[0] = i+2; 277 tri[1] = i+1; 278 tri[2] = i; 279 daIndices.append(tri); 280 281 tri[0] = i+5; 282 tri[1] = i+4; 283 tri[2] = i+3; 284 daIndices.append(tri); 285 } 286 else 287 { 288 tri[0] = i; 289 tri[1] = i+1; 290 tri[2] = i+2; 291 daIndices.append(tri); 292 293 tri[0] = i+3; 294 tri[1] = i+4; 295 tri[2] = i+5; 296 daIndices.append(tri); 297 } 298 299 i += 6; 300 } 301 } 302 303 /* 304 for(int w = 0; w < resolution; w++) 305 { 306 307 308 for(int h = (-resolution/2); h < (resolution/2); h++) 309 { 310 inc1 = (w/cast(float)resolution)*2*PI; 311 inc2 = ((w+1)/cast(float)resolution)*2*PI; 312 313 inc3 = (h/cast(float)resolution)*PI; 314 inc4 = ((h+1)/cast(float)resolution)*PI; 315 316 X1 = sin(inc1); 317 Y1 = cos(inc1); 318 X2 = sin(inc2); 319 Y2 = cos(inc2); 320 321 radius1 = radius*cos(inc3); 322 radius2 = radius*cos(inc4); 323 324 Z1 = radius*sin(inc3); 325 Z2 = radius*sin(inc4); 326 327 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 328 daVertices.append(Vector3f(radius1*X2,Z1,radius1*Y2)); 329 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 330 331 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 332 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 333 daVertices.append(Vector3f(radius2*X1,Z2,radius2*Y1)); 334 335 auto uv1 = Vector2f(0, 0); 336 auto uv2 = Vector2f(0, 1); 337 auto uv3 = Vector2f(1, 1); 338 auto uv4 = Vector2f(1, 0); 339 340 daTexcoords.append(uv1); 341 daTexcoords.append(uv2); 342 daTexcoords.append(uv3); 343 344 daTexcoords.append(uv1); 345 daTexcoords.append(uv3); 346 daTexcoords.append(uv4); 347 348 float sign = invNormals? -1.0f : 1.0f; 349 350 auto n1 = Vector3f(X1,Z1,Y1).normalized; 351 auto n2 = Vector3f(X2,Z1,Y2).normalized; 352 auto n3 = Vector3f(X2,Z2,Y2).normalized; 353 auto n4 = Vector3f(X1,Z2,Y1).normalized; 354 355 daNormals.append(n1 * sign); 356 daNormals.append(n2 * sign); 357 daNormals.append(n3 * sign); 358 359 daNormals.append(n1 * sign); 360 daNormals.append(n3 * sign); 361 daNormals.append(n4 * sign); 362 363 if (invNormals) 364 { 365 tri[0] = i+2; 366 tri[1] = i+1; 367 tri[2] = i; 368 daIndices.append(tri); 369 370 tri[0] = i+5; 371 tri[1] = i+4; 372 tri[2] = i+3; 373 daIndices.append(tri); 374 } 375 else 376 { 377 tri[0] = i; 378 tri[1] = i+1; 379 tri[2] = i+2; 380 daIndices.append(tri); 381 382 tri[0] = i+3; 383 tri[1] = i+4; 384 tri[2] = i+5; 385 daIndices.append(tri); 386 } 387 388 i += 6; 389 } 390 } 391 */ 392 393 vertices = New!(Vector3f[])(daVertices.length); 394 vertices[] = daVertices.data[]; 395 396 normals = New!(Vector3f[])(daNormals.length); 397 normals[] = daNormals.data[]; 398 399 texcoords = New!(Vector2f[])(daTexcoords.length); 400 texcoords[] = daTexcoords.data[]; 401 402 indices = New!(uint[3][])(daIndices.length); 403 indices[] = daIndices.data[]; 404 405 daVertices.free(); 406 daNormals.free(); 407 daTexcoords.free(); 408 daIndices.free(); 409 410 dataReady = true; 411 prepareVAO(); 412 } 413 } 414 415 // TODO: other shapes from original Dagon