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 import dlib.core.memory; 32 import dlib.math.vector; 33 import dlib.container.array; 34 import derelict.opengl; 35 import dagon.core.interfaces; 36 import dagon.core.ownership; 37 import dagon.graphics.mesh; 38 39 class ShapePlane: Mesh 40 { 41 this(float sx, float sz, uint numTiles, Owner owner) 42 { 43 super(owner); 44 45 float px = -sx * 0.5f; 46 float py = -sz * 0.5f; 47 48 float tileWidth = sx / numTiles; 49 float tileHeight = sz / numTiles; 50 51 Vector3f start = Vector3f(px, 0.0f, py); 52 53 uint gridSize = numTiles + 1; 54 55 vertices = New!(Vector3f[])(gridSize * gridSize); 56 normals = New!(Vector3f[])(gridSize * gridSize); 57 texcoords = New!(Vector2f[])(gridSize * gridSize); 58 59 for (uint i = 0, y = 0; y < gridSize; y++) 60 for (uint x = 0; x < gridSize; x++, i++) 61 { 62 vertices[i] = start + Vector3f(x * tileWidth, 0, y * tileHeight); 63 normals[i] = Vector3f(0, 1, 0); 64 texcoords[i] = Vector2f(x, y); 65 } 66 67 indices = New!(uint[3][])(gridSize * gridSize * 2); 68 69 uint index = 0; 70 for (uint y = 0; y < gridSize - 1; y++) 71 for (uint x = 0; x < gridSize - 1; x++) 72 { 73 uint offset = y * gridSize + x; 74 indices[index][2] = (offset + 0); 75 indices[index][1] = (offset + 1); 76 indices[index][0] = (offset + gridSize); 77 78 indices[index+1][2] = (offset + 1); 79 indices[index+1][1] = (offset + gridSize + 1); 80 indices[index+1][0] = (offset + gridSize); 81 82 index += 2; 83 } 84 85 dataReady = true; 86 prepareVAO(); 87 } 88 } 89 90 class ShapeQuad: Owner, Drawable 91 { 92 Vector2f[4] vertices; 93 Vector2f[4] texcoords; 94 uint[3][2] indices; 95 96 GLuint vao = 0; 97 GLuint vbo = 0; 98 GLuint tbo = 0; 99 GLuint eao = 0; 100 101 this(Owner o) 102 { 103 super(o); 104 105 vertices[0] = Vector2f(0, 1); 106 vertices[1] = Vector2f(0, 0); 107 vertices[2] = Vector2f(1, 0); 108 vertices[3] = Vector2f(1, 1); 109 110 texcoords[0] = Vector2f(0, 1); 111 texcoords[1] = Vector2f(0, 0); 112 texcoords[2] = Vector2f(1, 0); 113 texcoords[3] = Vector2f(1, 1); 114 115 indices[0][0] = 0; 116 indices[0][1] = 1; 117 indices[0][2] = 2; 118 119 indices[1][0] = 0; 120 indices[1][1] = 2; 121 indices[1][2] = 3; 122 123 glGenBuffers(1, &vbo); 124 glBindBuffer(GL_ARRAY_BUFFER, vbo); 125 glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof * 2, vertices.ptr, GL_STATIC_DRAW); 126 127 glGenBuffers(1, &tbo); 128 glBindBuffer(GL_ARRAY_BUFFER, tbo); 129 glBufferData(GL_ARRAY_BUFFER, texcoords.length * float.sizeof * 2, texcoords.ptr, GL_STATIC_DRAW); 130 131 glGenBuffers(1, &eao); 132 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 133 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length * uint.sizeof * 3, indices.ptr, GL_STATIC_DRAW); 134 135 glGenVertexArrays(1, &vao); 136 glBindVertexArray(vao); 137 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 138 139 glEnableVertexAttribArray(0); 140 glBindBuffer(GL_ARRAY_BUFFER, vbo); 141 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null); 142 143 glEnableVertexAttribArray(1); 144 glBindBuffer(GL_ARRAY_BUFFER, tbo); 145 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, null); 146 147 glBindVertexArray(0); 148 } 149 150 ~this() 151 { 152 glDeleteVertexArrays(1, &vao); 153 glDeleteBuffers(1, &vbo); 154 glDeleteBuffers(1, &tbo); 155 glDeleteBuffers(1, &eao); 156 } 157 158 void update(double dt) 159 { 160 } 161 162 void render(RenderingContext* rc) 163 { 164 glDepthMask(0); 165 glBindVertexArray(vao); 166 glDrawElements(GL_TRIANGLES, cast(uint)indices.length * 3, GL_UNSIGNED_INT, cast(void*)0); 167 glBindVertexArray(0); 168 glDepthMask(1); 169 } 170 } 171 172 enum PI2 = PI * 2.0f; 173 enum HALF_PI = PI * 0.5f; 174 175 Vector2f envMapEquirect(Vector3f dir) 176 { 177 //float phi = acos(dir.y); 178 //float theta = atan2(dir.x, dir.z) + PI; 179 //return Vector2f(theta / PI2, phi / PI); 180 Vector2f uv; 181 uv.y = acos(dir.y) / PI; 182 uv.x = (PI + atan2(dir.x, dir.z)) / PI2; 183 return uv; 184 } 185 186 class ShapeSphere: Mesh 187 { 188 DynamicArray!Vector3f daVertices; 189 DynamicArray!Vector3f daNormals; 190 DynamicArray!Vector2f daTexcoords; 191 DynamicArray!(uint[3]) daIndices; 192 193 this(float radius, int slices, int stacks, bool invNormals, Owner o) 194 { 195 super(o); 196 197 float X1, Y1, X2, Y2, Z1, Z2; 198 float inc1, inc2, inc3, inc4, inc5, radius1, radius2; 199 uint[3] tri; 200 uint i = 0; 201 202 float cuts = stacks; 203 float invCuts = 1.0f / cuts; 204 float heightStep = 2.0f * invCuts; 205 206 float invSlices = 1.0f / slices; 207 float angleStep = (2.0f * PI) * invSlices; 208 209 for(int h = 0; h < stacks; h++) 210 { 211 float h1Norm = cast(float)h * invCuts * 2.0f - 1.0f; 212 float h2Norm = cast(float)(h+1) * invCuts * 2.0f - 1.0f; 213 float y1 = sin(HALF_PI * h1Norm); 214 float y2 = sin(HALF_PI * h2Norm); 215 216 float circleRadius1 = cos(HALF_PI * y1); 217 float circleRadius2 = cos(HALF_PI * y2); 218 219 for(int a = 0; a < slices; a++) 220 { 221 float x1a = sin(angleStep * a) * circleRadius1; 222 float z1a = cos(angleStep * a) * circleRadius1; 223 float x2a = sin(angleStep * (a + 1)) * circleRadius1; 224 float z2a = cos(angleStep * (a + 1)) * circleRadius1; 225 226 float x1b = sin(angleStep * a) * circleRadius2; 227 float z1b = cos(angleStep * a) * circleRadius2; 228 float x2b = sin(angleStep * (a + 1)) * circleRadius2; 229 float z2b = cos(angleStep * (a + 1)) * circleRadius2; 230 231 Vector3f v1 = Vector3f(x1a, y1, z1a); 232 Vector3f v2 = Vector3f(x2a, y1, z2a); 233 Vector3f v3 = Vector3f(x1b, y2, z1b); 234 Vector3f v4 = Vector3f(x2b, y2, z2b); 235 236 Vector3f n1 = v1.normalized; 237 Vector3f n2 = v2.normalized; 238 Vector3f n3 = v3.normalized; 239 Vector3f n4 = v4.normalized; 240 241 daVertices.append(n1 * radius); 242 daVertices.append(n2 * radius); 243 daVertices.append(n3 * radius); 244 245 daVertices.append(n3 * radius); 246 daVertices.append(n2 * radius); 247 daVertices.append(n4 * radius); 248 249 float sign = invNormals? -1.0f : 1.0f; 250 251 daNormals.append(n1 * sign); 252 daNormals.append(n2 * sign); 253 daNormals.append(n3 * sign); 254 255 daNormals.append(n3 * sign); 256 daNormals.append(n2 * sign); 257 daNormals.append(n4 * sign); 258 259 auto uv1 = Vector2f(0, 1); 260 auto uv2 = Vector2f(1, 1); 261 auto uv3 = Vector2f(0, 0); 262 auto uv4 = Vector2f(1, 0); 263 264 daTexcoords.append(uv1); 265 daTexcoords.append(uv2); 266 daTexcoords.append(uv3); 267 268 daTexcoords.append(uv3); 269 daTexcoords.append(uv2); 270 daTexcoords.append(uv4); 271 272 if (invNormals) 273 { 274 tri[0] = i+2; 275 tri[1] = i+1; 276 tri[2] = i; 277 daIndices.append(tri); 278 279 tri[0] = i+5; 280 tri[1] = i+4; 281 tri[2] = i+3; 282 daIndices.append(tri); 283 } 284 else 285 { 286 tri[0] = i; 287 tri[1] = i+1; 288 tri[2] = i+2; 289 daIndices.append(tri); 290 291 tri[0] = i+3; 292 tri[1] = i+4; 293 tri[2] = i+5; 294 daIndices.append(tri); 295 } 296 297 i += 6; 298 } 299 } 300 301 /* 302 for(int w = 0; w < resolution; w++) 303 { 304 305 306 for(int h = (-resolution/2); h < (resolution/2); h++) 307 { 308 inc1 = (w/cast(float)resolution)*2*PI; 309 inc2 = ((w+1)/cast(float)resolution)*2*PI; 310 311 inc3 = (h/cast(float)resolution)*PI; 312 inc4 = ((h+1)/cast(float)resolution)*PI; 313 314 X1 = sin(inc1); 315 Y1 = cos(inc1); 316 X2 = sin(inc2); 317 Y2 = cos(inc2); 318 319 radius1 = radius*cos(inc3); 320 radius2 = radius*cos(inc4); 321 322 Z1 = radius*sin(inc3); 323 Z2 = radius*sin(inc4); 324 325 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 326 daVertices.append(Vector3f(radius1*X2,Z1,radius1*Y2)); 327 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 328 329 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1)); 330 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2)); 331 daVertices.append(Vector3f(radius2*X1,Z2,radius2*Y1)); 332 333 auto uv1 = Vector2f(0, 0); 334 auto uv2 = Vector2f(0, 1); 335 auto uv3 = Vector2f(1, 1); 336 auto uv4 = Vector2f(1, 0); 337 338 daTexcoords.append(uv1); 339 daTexcoords.append(uv2); 340 daTexcoords.append(uv3); 341 342 daTexcoords.append(uv1); 343 daTexcoords.append(uv3); 344 daTexcoords.append(uv4); 345 346 float sign = invNormals? -1.0f : 1.0f; 347 348 auto n1 = Vector3f(X1,Z1,Y1).normalized; 349 auto n2 = Vector3f(X2,Z1,Y2).normalized; 350 auto n3 = Vector3f(X2,Z2,Y2).normalized; 351 auto n4 = Vector3f(X1,Z2,Y1).normalized; 352 353 daNormals.append(n1 * sign); 354 daNormals.append(n2 * sign); 355 daNormals.append(n3 * sign); 356 357 daNormals.append(n1 * sign); 358 daNormals.append(n3 * sign); 359 daNormals.append(n4 * sign); 360 361 if (invNormals) 362 { 363 tri[0] = i+2; 364 tri[1] = i+1; 365 tri[2] = i; 366 daIndices.append(tri); 367 368 tri[0] = i+5; 369 tri[1] = i+4; 370 tri[2] = i+3; 371 daIndices.append(tri); 372 } 373 else 374 { 375 tri[0] = i; 376 tri[1] = i+1; 377 tri[2] = i+2; 378 daIndices.append(tri); 379 380 tri[0] = i+3; 381 tri[1] = i+4; 382 tri[2] = i+5; 383 daIndices.append(tri); 384 } 385 386 i += 6; 387 } 388 } 389 */ 390 391 vertices = New!(Vector3f[])(daVertices.length); 392 vertices[] = daVertices.data[]; 393 394 normals = New!(Vector3f[])(daNormals.length); 395 normals[] = daNormals.data[]; 396 397 texcoords = New!(Vector2f[])(daTexcoords.length); 398 texcoords[] = daTexcoords.data[]; 399 400 indices = New!(uint[3][])(daIndices.length); 401 indices[] = daIndices.data[]; 402 403 daVertices.free(); 404 daNormals.free(); 405 daTexcoords.free(); 406 daIndices.free(); 407 408 dataReady = true; 409 prepareVAO(); 410 } 411 } 412 413 // TODO: other shapes from original Dagon