├── QtTestShader.sln ├── QtTestShader.v11.suo ├── QtTestShader ├── Cubic.fsh ├── CurveRenderer.cpp ├── CurveRenderer.h ├── GLWidget.cpp ├── GLWidget.h ├── MyPoint.h ├── MyVector3.h ├── MyVertex.h ├── QtTestShader.cpp ├── QtTestShader.h ├── QtTestShader.ico ├── QtTestShader.qrc ├── QtTestShader.rc ├── QtTestShader.ui ├── QtTestShader.vcxproj ├── QtTestShader.vcxproj.filters ├── QtTestShader.vcxproj.user ├── Quad.fsh ├── VertexShader.vsh ├── main.cpp ├── stdafx.cpp └── stdafx.h ├── README.md └── bezier_large.png /QtTestShader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtTestShader", "QtTestShader\QtTestShader.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Build.0 = Debug|Win32 14 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32 15 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /QtTestShader.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azer89/GPU_Curve_Rendering/41380a44110256ca210b37de38239ac2d1f9070f/QtTestShader.v11.suo -------------------------------------------------------------------------------- /QtTestShader/Cubic.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | 4 | uniform vec4 insideColor; 5 | 6 | uniform vec4 outsideColor; 7 | 8 | 9 | void main(void) 10 | { 11 | vec3 uv = gl_TexCoord[0].xyz; 12 | float val = pow(uv.x, 3) - uv.y * uv.z; 13 | 14 | vec4 mycol = vec4(outsideColor.xyz, 1.0); 15 | 16 | if(val > 0.0 ) mycol = vec4(insideColor.xyz, 1.0); 17 | 18 | gl_FragColor = mycol; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /QtTestShader/CurveRenderer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdafx.h" 3 | #include "CurveRenderer.h" 4 | 5 | void CurveRenderer::ComputeCubic(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, int recursiveType) 6 | { 7 | double d0 = 0; double d1 = 0; double d2 = 0; double d3 = 0; 8 | CurveType curve_type = DetermineType(CVSystem::MyPoint(x0, y0), 9 | CVSystem::MyPoint(x1, y1), 10 | CVSystem::MyPoint(x2, y2), 11 | CVSystem::MyPoint(x3, y3), 12 | d0, d1, d2, d3); 13 | 14 | // debug 15 | curveTypeDebug = (int)curve_type; 16 | 17 | double OneThird = 1.0f / 3.0f; 18 | double TwoThirds = 2.0f / 3.0f; 19 | 20 | float t1; 21 | float ls; 22 | float lt; 23 | float ms; 24 | float mt; 25 | 26 | float ltMinusLs; 27 | float mtMinusMs; 28 | float lsMinusLt; 29 | float ql; 30 | float qm; 31 | 32 | // bool flip 33 | bool flip = false; 34 | 35 | // artifact on loop 36 | int errorLoop = -1; 37 | double splitParam = 0; 38 | 39 | std::vector klm(12); 40 | 41 | 42 | switch (curve_type) 43 | { 44 | case CURVE_TYPE_UNKNOWN: 45 | break; 46 | 47 | case CURVE_TYPE_SERPENTINE: 48 | 49 | t1 = sqrtf(9.0f * d2 * d2 - 12 * d1 * d3); 50 | ls = 3.0f * d2 - t1; 51 | lt = 6.0f * d1; 52 | ms = 3.0f * d2 + t1; 53 | mt = lt; 54 | ltMinusLs = lt - ls; 55 | mtMinusMs = mt - ms; 56 | 57 | klm[0] = ls * ms; 58 | klm[1] = ls * ls * ls; 59 | klm[2] = ms * ms * ms; 60 | 61 | klm[3] = OneThird * (3.0f * ls * ms - ls * mt - lt * ms); 62 | klm[4] = ls * ls * (ls - lt); 63 | klm[5] = ms * ms * (ms - mt); 64 | 65 | klm[6] = OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)); 66 | klm[7] = ltMinusLs * ltMinusLs * ls; 67 | klm[8] = mtMinusMs * mtMinusMs * ms; 68 | 69 | klm[9] = ltMinusLs * mtMinusMs; 70 | klm[10] = -(ltMinusLs * ltMinusLs * ltMinusLs); 71 | klm[11] = -(mtMinusMs * mtMinusMs * mtMinusMs); 72 | 73 | if (d1 < 0.0f) 74 | flip = true; 75 | 76 | break; 77 | 78 | case CURVE_TYPE_LOOP: 79 | 80 | t1 = sqrtf(4.0f * d1 * d3 - 3.0f * d2 * d2); 81 | ls = d2 - t1; 82 | lt = 2.0f * d1; 83 | ms = d2 + t1; 84 | mt = lt; 85 | 86 | // Figure out whether there is a rendering artifact requiring 87 | // the curve to be subdivided by the caller. 88 | ql = ls / lt; 89 | qm = ms / mt; 90 | if (0.0f < ql && ql < 1.0f) 91 | { 92 | errorLoop = 1; 93 | splitParam = ql; 94 | //std::cout << "error loop 1\n"; 95 | } 96 | 97 | if (0.0f < qm && qm < 1.0f) 98 | { 99 | errorLoop = 2; 100 | splitParam = qm; 101 | 102 | //std::cout << "error loop 2\n"; 103 | } 104 | 105 | ltMinusLs = lt - ls; 106 | mtMinusMs = mt - ms; 107 | klm[0] = ls * ms; 108 | klm[1] = ls * ls * ms; 109 | klm[2] = ls * ms * ms; 110 | 111 | klm[3] = OneThird * (-ls * mt - lt * ms + 3.0f * ls * ms); 112 | klm[4] = -OneThird * ls * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms); 113 | klm[5] = -OneThird * ms * (ls * (2.0f * mt - 3.0f * ms) + lt * ms); 114 | 115 | klm[6] = OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)); 116 | klm[7] = OneThird * (lt - ls) * (ls * (2.0f * mt - 3.0f * ms) + lt * ms); 117 | klm[8] = OneThird * (mt - ms) * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms); 118 | 119 | klm[9] = ltMinusLs * mtMinusMs; 120 | klm[10] = -(ltMinusLs * ltMinusLs) * mtMinusMs; 121 | klm[11] = -ltMinusLs * mtMinusMs * mtMinusMs; 122 | 123 | if (recursiveType == -1) 124 | flip = ((d1 > 0.0f && klm[0] < 0.0f) || (d1 < 0.0f && klm[0] > 0.0f)); 125 | 126 | break; 127 | 128 | case CURVE_TYPE_CUSP: 129 | ls = d3; 130 | lt = 3.0f * d2; 131 | lsMinusLt = ls - lt; 132 | klm[0] = ls; 133 | klm[1] = ls * ls * ls; 134 | klm[2] = 1.0f; 135 | 136 | klm[3] = ls - OneThird * lt; 137 | klm[4] = ls * ls * lsMinusLt; 138 | klm[5] = 1.0f; 139 | 140 | klm[6] = ls - TwoThirds * lt; 141 | klm[7] = lsMinusLt * lsMinusLt * ls; 142 | klm[8] = 1.0f; 143 | 144 | klm[9] = lsMinusLt; 145 | klm[10] = lsMinusLt * lsMinusLt * lsMinusLt; 146 | klm[11] = 1.0f; 147 | 148 | break; 149 | 150 | case CURVE_TYPE_QUADRATIC: 151 | klm[0] = 0; 152 | klm[1] = 0; 153 | klm[2] = 0; 154 | 155 | klm[3] = OneThird; 156 | klm[4] = 0; 157 | klm[5] = OneThird; 158 | 159 | klm[6] = TwoThirds; 160 | klm[7] = OneThird; 161 | klm[8] = TwoThirds; 162 | 163 | klm[9] = 1; 164 | klm[10] = 1; 165 | klm[11] = 1; 166 | 167 | if (d3 < 0) 168 | flip = true; 169 | 170 | break; 171 | 172 | case CURVE_TYPE_LINE: 173 | break; 174 | } 175 | 176 | if (errorLoop != -1 && recursiveType == -1) 177 | { 178 | double x01 = (x1 - x0) * splitParam + x0; double x12 = (x2 - x1) * splitParam + x1; double x23 = (x3 - x2) * splitParam + x2; 179 | double y01 = (y1 - y0) * splitParam + y0; double y12 = (y2 - y1) * splitParam + y1; double y23 = (y3 - y2) * splitParam + y2; 180 | 181 | double x012 = (x12 - x01) * splitParam + x01; double x123 = (x23 - x12) * splitParam + x12; 182 | double y012 = (y12 - y01) * splitParam + y01; double y123 = (y23 - y12) * splitParam + y12; 183 | 184 | double x0123 = (x123 - x012) * splitParam + x012; 185 | double y0123 = (y123 - y012) * splitParam + y012; 186 | 187 | 188 | 189 | drawAdditionalTri = true; 190 | atri[0] = CVSystem::MyPoint(x0, y0); 191 | atri[1] = CVSystem::MyPoint(x0123, y0123); 192 | atri[2] = CVSystem::MyPoint(x3, y3); 193 | //DrawPlainTriangle(atri[0].x, atri[0].y, atri[1].x, atri[1].y, atri[2].x, atri[2].y); 194 | 195 | 196 | if (errorLoop == 1) // flip second 197 | { 198 | ComputeCubic(x0, y0, x01, y01, x012, y012, x0123, y0123, 0); 199 | ComputeCubic(x0123, y0123, x123, y123, x23, y23, x3, y3, 1); 200 | } 201 | else if (errorLoop == 2) // flip first 202 | { 203 | ComputeCubic(x0, y0, x01, y01, x012, y012, x0123, y0123, 1); 204 | ComputeCubic(x0123, y0123, x123, y123, x23, y23, x3, y3, 0); 205 | } 206 | 207 | /*if(flip) 208 | { 209 | DrawPlainTriangle(x0, y0, x0123, y0123, x3, y3, false); 210 | } 211 | else 212 | { 213 | DrawPlainTriangle(x0, y0, x0123, y0123, x3, y3, true); 214 | }*/ 215 | 216 | return; 217 | } 218 | else if (errorLoop == -1 && recursiveType == -1) 219 | { 220 | drawAdditionalTri = false; 221 | } 222 | 223 | if (recursiveType == 1) 224 | flip = !flip; 225 | 226 | if (flip) 227 | { 228 | klm[0] = -klm[0]; klm[1] = -klm[1]; 229 | klm[3] = -klm[3]; klm[4] = -klm[4]; 230 | klm[6] = -klm[6]; klm[7] = -klm[7]; 231 | klm[9] = -klm[9]; klm[10] = -klm[10]; 232 | } 233 | 234 | Triangulation(x0, y0, x1, y1, x2, y2, x3, y3, klm); 235 | 236 | //if(recursiveType != -1) 237 | //{ 238 | // DrawPlainTriangle(atri[0].x, atri[0].y, atri[1].x, atri[1].y, atri[2].x, atri[2].y); 239 | //} 240 | 241 | //if(drawAdditionalTri) 242 | //{ 243 | // std::cout << "error loop\n"; 244 | // DrawPlainTriangle(atri[0].x, atri[0].y, atri[1].x, atri[1].y, atri[2].x, atri[2].y, false); 245 | //} 246 | 247 | 248 | } 249 | 250 | void CurveRenderer::Triangulation(double x0, double y0, 251 | double x1, double y1, 252 | double x2, double y2, 253 | double x3, double y3, 254 | std::vector klm) 255 | { 256 | std::vector vertices; 257 | vertices.push_back(MyVertex(x0, y0, klm[0], klm[1], klm[2])); 258 | vertices.push_back(MyVertex(x1, y1, klm[3], klm[4], klm[5])); 259 | vertices.push_back(MyVertex(x2, y2, klm[6], klm[7], klm[8])); 260 | vertices.push_back(MyVertex(x3, y3, klm[9], klm[10], klm[11])); 261 | 262 | // First test for degenerate cases. 263 | for (int i = 0; i < 4; ++i) 264 | { 265 | for (int j = i + 1; j < 4; ++j) 266 | { 267 | if (ApproxEqual(vertices[i].xyCoor, vertices[j].xyCoor)) 268 | { 269 | // Two of the vertices are coincident, so we can eliminate at 270 | // least one triangle. We might be able to eliminate the other 271 | // as well, but this seems sufficient to avoid degenerate 272 | // triangulations. 273 | int indices[3] = { 0 }; 274 | int index = 0; 275 | for (int k = 0; k < 4; ++k) 276 | if (k != j) 277 | indices[index++] = k; 278 | 279 | DrawTriangle(vertices[indices[0]], 280 | vertices[indices[1]], 281 | vertices[indices[2]]); 282 | 283 | return; 284 | } 285 | } 286 | } 287 | 288 | // See whether any of the points are fully contained in the 289 | // triangle defined by the other three. 290 | for (int i = 0; i < 4; ++i) 291 | { 292 | int indices[3] = { 0 }; 293 | int index = 0; 294 | for (int j = 0; j < 4; ++j) 295 | if (i != j) 296 | indices[index++] = j; 297 | 298 | if (PointInTriangle(vertices[i].xyCoor, vertices[indices[0]].xyCoor, vertices[indices[1]].xyCoor, vertices[indices[2]].xyCoor)) 299 | { 300 | // Produce three triangles surrounding this interior vertex. 301 | for (int j = 0; j < 3; ++j) 302 | DrawTriangle(vertices[indices[j % 3]], vertices[indices[(j + 1) % 3]], vertices[i]); 303 | 304 | // Mark the interior vertex so we ignore it if trying to trace 305 | // the interior edge ? 306 | //m_vertices[i].setInterior(true); 307 | return; 308 | } 309 | } 310 | 311 | // There are only a few permutations of the vertices, ignoring 312 | // rotations, which are irrelevant: 313 | // 314 | // 0--3 0--2 0--3 0--1 0--2 0--1 315 | // | | | | | | | | | | | | 316 | // | | | | | | | | | | | | 317 | // 1--2 1--3 2--1 2--3 3--1 3--2 318 | // 319 | // Note that three of these are reflections of each other. 320 | // Therefore there are only three possible triangulations: 321 | // 322 | // 0--3 0--2 0--3 323 | // |\ | |\ | |\ | 324 | // | \| | \| | \| 325 | // 1--2 1--3 2--1 326 | // 327 | // From which we can choose by seeing which of the potential 328 | // diagonals intersect. Note that we choose the shortest diagonal 329 | // to split the quad. 330 | if (LinesIntersect(vertices[0].xyCoor, vertices[2].xyCoor, vertices[1].xyCoor, vertices[3].xyCoor)) 331 | { 332 | if ((vertices[2].xyCoor - vertices[0].xyCoor).DiagonalLengthSquared() < (vertices[3].xyCoor - vertices[1].xyCoor).DiagonalLengthSquared()) 333 | { 334 | DrawTriangle(vertices[0], vertices[1], vertices[2]); 335 | DrawTriangle(vertices[0], vertices[2], vertices[3]); 336 | } 337 | else 338 | { 339 | DrawTriangle(vertices[0], vertices[1], vertices[3]); 340 | DrawTriangle(vertices[1], vertices[2], vertices[3]); 341 | } 342 | } 343 | else if (LinesIntersect(vertices[0].xyCoor, vertices[3].xyCoor, vertices[1].xyCoor, vertices[2].xyCoor)) 344 | { 345 | if ((vertices[3].xyCoor - vertices[0].xyCoor).DiagonalLengthSquared() < (vertices[2].xyCoor - vertices[1].xyCoor).DiagonalLengthSquared()) 346 | { 347 | DrawTriangle(vertices[0], vertices[1], vertices[3]); 348 | DrawTriangle(vertices[0], vertices[3], vertices[2]); 349 | } 350 | else 351 | { 352 | DrawTriangle(vertices[0], vertices[1], vertices[2]); 353 | DrawTriangle(vertices[2], vertices[1], vertices[3]); 354 | } 355 | } 356 | else 357 | { 358 | // Lines (0->1), (2->3) intersect -- or should, modulo numerical 359 | // precision issues 360 | if ((vertices[1].xyCoor - vertices[0].xyCoor).DiagonalLengthSquared() < (vertices[3].xyCoor - vertices[2].xyCoor).DiagonalLengthSquared()) 361 | { 362 | DrawTriangle(vertices[0], vertices[2], vertices[1]); 363 | DrawTriangle(vertices[0], vertices[1], vertices[3]); 364 | } 365 | else 366 | { 367 | DrawTriangle(vertices[0], vertices[2], vertices[3]); 368 | DrawTriangle(vertices[3], vertices[2], vertices[1]); 369 | } 370 | } 371 | } 372 | 373 | void CurveRenderer::DrawPlainTriangle(double x0, double y0, 374 | double x1, double y1, 375 | double x2, double y2) 376 | { 377 | //glDepthMask(GL_FALSE); 378 | //glEnable(GL_BLEND); 379 | //glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); 380 | 381 | glColor4f(0.0, 0.0, 0.0, 1.0); 382 | glBegin(GL_TRIANGLES); 383 | glVertex3f(x0, y0, 0.0f); 384 | glVertex3f(x1, y1, 0.0f); 385 | glVertex3f(x2, y2, 0.0f); 386 | glEnd(); 387 | 388 | //glDisable(GL_BLEND); 389 | //glDepthMask(GL_TRUE); 390 | } 391 | 392 | void CurveRenderer::DrawPlainTriangle(double x0, double y0, double x1, double y1, double x2, double y2, bool isInside) 393 | { 394 | if (isInside) 395 | { 396 | glColor4f(0.0, 0.0, 0.0, 1.0); 397 | } 398 | else 399 | { 400 | glColor4f(1.0, 1.0, 0.0, 1.0); 401 | } 402 | 403 | glBegin(GL_TRIANGLES); 404 | glVertex3f(x0, y0, 0.0f); 405 | glVertex3f(x1, y1, 0.0f); 406 | glVertex3f(x2, y2, 0.0f); 407 | glEnd(); 408 | } 409 | 410 | void CurveRenderer::DrawTriangle(MyVertex v0, 411 | MyVertex v1, 412 | MyVertex v2) 413 | { 414 | //std::cout << "draw\n"; 415 | 416 | shaderProgram->setUniformValue("insideColor", QColor(Qt::black)); 417 | shaderProgram->setUniformValue("outsideColor", QColor(Qt::white)); 418 | 419 | glDepthMask(GL_FALSE); 420 | glEnable(GL_BLEND); 421 | glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); 422 | 423 | 424 | 425 | glBegin(GL_TRIANGLES); 426 | glTexCoord3f(v0.k, v0.l, v0.m); 427 | glVertex3f(v0.xyCoor.x, v0.xyCoor.y, 0.0f); 428 | 429 | glTexCoord3f(v1.k, v1.l, v1.m); 430 | glVertex3f(v1.xyCoor.x, v1.xyCoor.y, 0.0f); 431 | 432 | glTexCoord3f(v2.k, v2.l, v2.m); 433 | glVertex3f(v2.xyCoor.x, v2.xyCoor.y, 0.0f); 434 | glEnd(); 435 | 436 | 437 | glDisable(GL_BLEND); 438 | glDepthMask(GL_TRUE); 439 | } 440 | 441 | 442 | CurveType CurveRenderer::DetermineType(CVSystem::MyPoint v0, 443 | CVSystem::MyPoint v1, 444 | CVSystem::MyPoint v2, 445 | CVSystem::MyPoint v3, 446 | double& d0, 447 | double& d1, 448 | double& d2, 449 | double& d3) 450 | { 451 | d0 = 0; 452 | 453 | Eigen::Vector3d b0(v0.x, v0.y, 1.0f); 454 | Eigen::Vector3d b1(v1.x, v1.y, 1.0f); 455 | Eigen::Vector3d b2(v2.x, v2.y, 1.0f); 456 | Eigen::Vector3d b3(v3.x, v3.y, 1.0f); 457 | 458 | double a1 = b0.dot(b3.cross(b2)); 459 | double a2 = b1.dot(b0.cross(b3)); 460 | double a3 = b2.dot(b1.cross(b0)); 461 | 462 | d1 = a1 - 2 * a2 + 3 * a3; 463 | d2 = -a2 + 3 * a3; 464 | d3 = 3 * a3; 465 | 466 | // normalize? 467 | /*double length = sqrt(d0 * d0 + d1 * d1 + d2* d2 + d3 * d3); 468 | d0 /= length; 469 | d1 /= length; 470 | d2 /= length; 471 | d3 /= length;*/ 472 | 473 | double D = 3.0 * d2 * d2 - 4.0 * d1 * d3; 474 | double disc = d1 * d1 * D; 475 | 476 | /*if (disc > -M_EPS && disc < M_EPS) 477 | disc = 0; 478 | 479 | if (d0 > -M_EPS && d0 < M_EPS) 480 | d0 = 0; 481 | 482 | if (d1 > -M_EPS && d1 < M_EPS) 483 | d1 = 0; 484 | 485 | if (d2 > -M_EPS && d2 < M_EPS) 486 | d2 = 0; 487 | 488 | if (d3 > -M_EPS && d3 < M_EPS) 489 | d3 = 0; 490 | */ 491 | //curve_type = CURVE_TYPE_UNKNOWN; 492 | 493 | if (!disc) 494 | { 495 | if (!d1 && !d2) 496 | { 497 | if (!d3) 498 | { 499 | return CURVE_TYPE_LINE; 500 | } 501 | 502 | return CURVE_TYPE_QUADRATIC; 503 | } 504 | 505 | if (d1 != 0) 506 | { 507 | return CURVE_TYPE_CUSP; 508 | } 509 | 510 | if (D < 0) 511 | return CURVE_TYPE_LOOP; 512 | 513 | return CURVE_TYPE_SERPENTINE; 514 | } 515 | 516 | if (disc > 0) return CURVE_TYPE_SERPENTINE; 517 | 518 | // discriminant < 0 519 | return CURVE_TYPE_LOOP; 520 | } 521 | 522 | bool CurveRenderer::ApproxEqual(CVSystem::MyPoint& v0, CVSystem::MyPoint& v1) 523 | { 524 | return (v0 - v1).DiagonalLengthSquared() < M_EPS * M_EPS; 525 | } 526 | 527 | bool CurveRenderer::PointInTriangle(CVSystem::MyPoint& point, 528 | CVSystem::MyPoint& a, 529 | CVSystem::MyPoint& b, 530 | CVSystem::MyPoint& c) 531 | { 532 | // Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html 533 | float x0 = c.x - a.x; 534 | float y0 = c.y - a.y; 535 | float x1 = b.x - a.x; 536 | float y1 = b.y - a.y; 537 | float x2 = point.x - a.x; 538 | float y2 = point.y - a.y; 539 | 540 | float dot00 = x0 * x0 + y0 * y0; 541 | float dot01 = x0 * x1 + y0 * y1; 542 | float dot02 = x0 * x2 + y0 * y2; 543 | float dot11 = x1 * x1 + y1 * y1; 544 | float dot12 = x1 * x2 + y1 * y2; 545 | float denominator = dot00 * dot11 - dot01 * dot01; 546 | if (!denominator) 547 | // Triangle is zero-area. Treat query point as not being inside. 548 | return false; 549 | // Compute 550 | float inverseDenominator = 1.0f / denominator; 551 | float u = (dot11 * dot02 - dot01 * dot12) * inverseDenominator; 552 | float v = (dot00 * dot12 - dot01 * dot02) * inverseDenominator; 553 | 554 | return (u > 0.0f) && (v > 0.0f) && (u + v < 1.0f); 555 | } 556 | 557 | // Utility functions local to this file. 558 | int CurveRenderer::Orientation(CVSystem::MyPoint& p1, 559 | CVSystem::MyPoint& p2, 560 | CVSystem::MyPoint& p3) 561 | { 562 | float crossProduct = (p2.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p2.x - p1.x); 563 | return (crossProduct < 0.0f) ? -1 : ((crossProduct > 0.0f) ? 1 : 0); 564 | } 565 | 566 | bool CurveRenderer::LinesIntersect(CVSystem::MyPoint& p1, 567 | CVSystem::MyPoint& q1, 568 | CVSystem::MyPoint& p2, 569 | CVSystem::MyPoint& q2) 570 | { 571 | return (Orientation(p1, q1, p2) != Orientation(p1, q1, q2) 572 | && Orientation(p2, q2, p1) != Orientation(p2, q2, q1)); 573 | } 574 | 575 | -------------------------------------------------------------------------------- /QtTestShader/CurveRenderer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __VECTORRENDERER_H__ 3 | #define __VECTORRENDERER_H__ 4 | 5 | #include "stdafx.h" 6 | 7 | #include "MyPoint.h" 8 | #include "MyVector3.h" 9 | #include "MyVertex.h" 10 | 11 | #include 12 | 13 | #include 14 | 15 | typedef enum _CurveType 16 | { 17 | CURVE_TYPE_UNKNOWN = 0, 18 | CURVE_TYPE_SERPENTINE = 1, 19 | CURVE_TYPE_LOOP = 2, 20 | CURVE_TYPE_CUSP = 3, 21 | CURVE_TYPE_QUADRATIC = 4, 22 | CURVE_TYPE_LINE = 5, 23 | 24 | } CurveType; 25 | 26 | class CurveRenderer 27 | { 28 | public: 29 | CurveRenderer() { 30 | drawAdditionalTri = false; 31 | atri = std::vector(3); 32 | } 33 | ~CurveRenderer(){} 34 | 35 | QGLShaderProgram* shaderProgram; 36 | int curveTypeDebug; 37 | 38 | void ComputeCubic (float x0, float y0, 39 | float x1, float y1, 40 | float x2, float y2, 41 | float x3, float y3, 42 | int recursiveType = -1); 43 | 44 | CurveType DetermineType (CVSystem::MyPoint v0, CVSystem::MyPoint v1, 45 | CVSystem::MyPoint v2, CVSystem::MyPoint v3, 46 | double& d0, double& d1, 47 | double& d2, double& d3); 48 | 49 | void Triangulation (double x0, double y0, 50 | double x1, double y1, 51 | double x2, double y2, 52 | double x3, double y3, 53 | std::vector klm); 54 | 55 | void DrawTriangle (MyVertex v0, MyVertex v1, MyVertex v2); 56 | 57 | void DrawPlainTriangle (double x0, double y0, 58 | double x1, double y1, 59 | double x2, double y2); 60 | 61 | void DrawPlainTriangle (double x0, double y0, 62 | double x1, double y1, 63 | double x2, double y2, 64 | bool isInside); 65 | 66 | bool ApproxEqual(CVSystem::MyPoint& v0, CVSystem::MyPoint& v1); 67 | bool PointInTriangle(CVSystem::MyPoint& point, CVSystem::MyPoint& a, CVSystem::MyPoint& b, CVSystem::MyPoint& c); 68 | int Orientation(CVSystem::MyPoint& p1, CVSystem::MyPoint& p2, CVSystem::MyPoint& p3); 69 | bool LinesIntersect(CVSystem::MyPoint& p1, CVSystem::MyPoint& q1, CVSystem::MyPoint& p2, CVSystem::MyPoint& q2); 70 | 71 | public: 72 | bool drawAdditionalTri; 73 | std::vector atri; 74 | }; 75 | 76 | #endif -------------------------------------------------------------------------------- /QtTestShader/GLWidget.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdafx.h" 3 | #include "GLWidget.h" 4 | #include "MyPoint.h" 5 | 6 | GLWidget::GLWidget(QGLFormat format, QWidget *parent) : 7 | QGLWidget(format, parent), 8 | cRenderer(0), 9 | pressIdx(-1) 10 | { 11 | cRenderer = new CurveRenderer(); 12 | 13 | /* 14 | // Case loop artifact #1 15 | points.push_back(CVSystem::MyPoint(108, 530)); 16 | points.push_back(CVSystem::MyPoint(117, 74)); 17 | points.push_back(CVSystem::MyPoint(639, 227)); 18 | points.push_back(CVSystem::MyPoint(896, 368)); 19 | */ 20 | 21 | // Case loop artifact #2 22 | points.push_back(CVSystem::MyPoint(154, 670)); 23 | points.push_back(CVSystem::MyPoint(368, 511)); 24 | points.push_back(CVSystem::MyPoint(722, 354)); 25 | points.push_back(CVSystem::MyPoint(932, 551)); 26 | 27 | } 28 | 29 | GLWidget::~GLWidget() 30 | { 31 | if(cRenderer) delete cRenderer; 32 | } 33 | 34 | void GLWidget::initializeGL() 35 | { 36 | glClearColor(0.75, 0.75, 0.75, 1.0); 37 | 38 | //shaderProgram.addShaderFromSourceFile(QGLShader::Vertex, "VertexShader.vsh"); 39 | shaderProgram.addShaderFromSourceFile(QGLShader::Fragment, "Cubic.fsh"); 40 | shaderProgram.link(); 41 | 42 | cRenderer->shaderProgram = &shaderProgram; 43 | } 44 | 45 | void GLWidget::resizeGL( int width, int height ) 46 | { 47 | } 48 | 49 | bool GLWidget::event( QEvent * event ) { return QGLWidget::event(event); } 50 | 51 | /* void GLWidget::resizeGL(int width, int height) { QGLWidget::resizeGL(width, height); }*/ 52 | 53 | void GLWidget::paintGL() 54 | { 55 | glViewport(0, 0, this->width(), this->height()); 56 | 57 | glMatrixMode(GL_PROJECTION); 58 | glLoadIdentity(); 59 | 60 | gluOrtho2D(0, this->width(), this->height(), 0); // flip the y axis 61 | 62 | glMatrixMode(GL_MODELVIEW); 63 | glLoadIdentity(); 64 | glScalef(1, 1, 1); 65 | 66 | glClear(GL_COLOR_BUFFER_BIT); 67 | 68 | /*GLfloat m1[16]; 69 | glGetFloatv(GL_MODELVIEW_MATRIX, m1); 70 | QMatrix4x4 mv_mat( m1[0],m1[1],m1[2],m1[3], 71 | m1[4],m1[5],m1[6],m1[7], 72 | m1[8],m1[9],m1[10],m1[11], 73 | m1[12],m1[13],m1[14],m1[15]); 74 | 75 | GLfloat m2[16]; 76 | glGetFloatv(GL_PROJECTION_MATRIX, m2); 77 | QMatrix4x4 p_mat( m2[0], m2[1], m2[2], m2[3], 78 | m2[4], m2[5], m2[6], m2[7], 79 | m2[8], m2[9], m2[10],m2[11], 80 | m2[12],m2[13],m2[14],m2[15]);*/ 81 | 82 | shaderProgram.bind(); 83 | 84 | //shaderProgram.setUniformValue("mat", mv_mat * p_mat); 85 | //shaderProgram.setUniformValue("color", QColor(Qt::red 86 | 87 | /* 88 | // Demo for quadratic curve 89 | glBegin(GL_TRIANGLES); 90 | 91 | glTexCoord2f(0.0f, 0.0f); 92 | glVertex3f(15, 15, 0); 93 | 94 | glTexCoord2f(0.5f, 0.0f); 95 | glVertex3f(25, 90, 0); 96 | 97 | glTexCoord2f(1.0f, 1.0f); 98 | glVertex3f(90, 25, 0); 99 | 100 | glEnd();*/ 101 | 102 | cRenderer->ComputeCubic( points[0].x, points[0].y, 103 | points[1].x, points[1].y, 104 | points[2].x, points[2].y, 105 | points[3].x, points[3].y); 106 | 107 | shaderProgram.release(); 108 | 109 | if(cRenderer->drawAdditionalTri) 110 | cRenderer->DrawPlainTriangle(cRenderer->atri[0].x, cRenderer->atri[0].y, cRenderer->atri[1].x, cRenderer->atri[1].y, cRenderer->atri[2].x, cRenderer->atri[2].y); 111 | 112 | /* 113 | DrawLine(cRenderer->t1[0].x, cRenderer->t1[0].y, cRenderer->t2[0].x, cRenderer->t2[0].y); 114 | DrawLine(cRenderer->t2[0].x, cRenderer->t2[0].y, cRenderer->t3[0].x, cRenderer->t3[0].y); 115 | DrawLine(cRenderer->t3[0].x, cRenderer->t3[0].y, cRenderer->t1[0].x, cRenderer->t1[0].y); 116 | 117 | DrawLine(cRenderer->t1[1].x, cRenderer->t1[1].y, cRenderer->t2[1].x, cRenderer->t2[1].y); 118 | DrawLine(cRenderer->t2[1].x, cRenderer->t2[1].y, cRenderer->t3[1].x, cRenderer->t3[1].y); 119 | DrawLine(cRenderer->t3[1].x, cRenderer->t3[1].y, cRenderer->t1[1].x, cRenderer->t1[1].y); 120 | 121 | DrawLine(cRenderer->t1[2].x, cRenderer->t1[2].y, cRenderer->t2[2].x, cRenderer->t2[2].y); 122 | DrawLine(cRenderer->t2[2].x, cRenderer->t2[2].y, cRenderer->t3[2].x, cRenderer->t3[2].y); 123 | DrawLine(cRenderer->t3[2].x, cRenderer->t3[2].y, cRenderer->t1[2].x, cRenderer->t1[2].y);*/ 124 | 125 | DrawLine(points[0].x, points[0].y, points[1].x, points[1].y); 126 | DrawLine(points[2].x, points[2].y, points[3].x, points[3].y); 127 | 128 | DrawCircle(points[0], 15, 0, 1.0, 0.0, 1.0); 129 | DrawCircle(points[1], 15, 0, 1.0, 0, 1.0); 130 | DrawCircle(points[2], 15, 0, 1.0, 0, 1.0); 131 | DrawCircle(points[3], 15, 0, 1.0, 0.0, 1.0); 132 | 133 | 134 | } 135 | 136 | void GLWidget::DrawCircle(CVSystem::MyPoint pt, float radius, double r, double g, double b, double a) 137 | { 138 | glDepthMask(GL_FALSE); 139 | glEnable(GL_BLEND); 140 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 141 | 142 | float delta_theta = 0.01; 143 | 144 | glColor4f(r, g, b, a); 145 | glBegin( GL_POLYGON ); 146 | 147 | for( float angle = 0; angle < 2* M_PI; angle += delta_theta ) 148 | glVertex3f( pt.x + radius * cos(angle), pt.y + radius * sin(angle), 0 ); 149 | 150 | glEnd(); 151 | glDisable(GL_BLEND); 152 | glDepthMask(GL_TRUE); 153 | } 154 | 155 | void GLWidget::DrawLine(float x1, float y1, float x2, float y2) 156 | { 157 | glDepthMask(GL_FALSE); 158 | glLineWidth(3.0); 159 | glColor4f(1, 0, 0, 1.0); 160 | 161 | glBegin(GL_LINES); 162 | 163 | glVertex3f(x1, y1, 0); 164 | glVertex3f(x2, y2, 0); 165 | 166 | glEnd(); 167 | glDepthMask(GL_TRUE); 168 | } 169 | 170 | void GLWidget::mousePressEvent(QMouseEvent *event) 171 | { 172 | CVSystem::MyPoint cP(event->x(), event->y()); 173 | for(int a = 0; a < points.size(); a++) 174 | { 175 | float d = points[a].Distance(cP); 176 | if(d < 10.0f) 177 | { 178 | pressIdx = a; 179 | break; 180 | } 181 | } 182 | 183 | if(pressIdx >= 0) 184 | { 185 | points[pressIdx].x = event->x(); 186 | points[pressIdx].y = event->y(); 187 | this->updateGL(); 188 | } 189 | } 190 | 191 | void GLWidget::mouseMoveEvent(QMouseEvent *event) 192 | { 193 | if(pressIdx >= 0) 194 | { 195 | points[pressIdx].x = event->x(); 196 | points[pressIdx].y = event->y(); 197 | this->updateGL(); 198 | } 199 | } 200 | 201 | void GLWidget::mouseReleaseEvent(QMouseEvent *event) 202 | { 203 | if(pressIdx >= 0) 204 | { 205 | points[pressIdx].x = event->x(); 206 | points[pressIdx].y = event->y(); 207 | this->updateGL(); 208 | } 209 | pressIdx = -1; 210 | } 211 | -------------------------------------------------------------------------------- /QtTestShader/GLWidget.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __GLWIDGET_H__ 3 | #define __GLWIDGET_H__ 4 | 5 | #include "stdafx.h" 6 | #include "CurveRenderer.h" 7 | #include "MyPoint.h" 8 | 9 | //#include 10 | 11 | 12 | class GLWidget : public QGLWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | GLWidget(QGLFormat format, QWidget *parent = 0); 18 | ~GLWidget(); 19 | 20 | void DrawCircle(CVSystem::MyPoint pt, float radius, double r, double g, double b, double a); 21 | void DrawLine(float x1, float y1, float x2, float y2); 22 | 23 | int GetCurveType() 24 | { 25 | return cRenderer->curveTypeDebug; 26 | } 27 | 28 | protected: 29 | bool event( QEvent * event ); 30 | void initializeGL(); 31 | void paintGL(); 32 | void resizeGL(int w, int h); 33 | 34 | void mousePressEvent(QMouseEvent *event); 35 | void mouseMoveEvent(QMouseEvent *event); 36 | void mouseReleaseEvent(QMouseEvent *event); 37 | 38 | private: 39 | 40 | CurveRenderer* cRenderer; 41 | std::vector points; 42 | 43 | QMatrix4x4 pMatrix; 44 | QGLShaderProgram shaderProgram; 45 | 46 | int pressIdx; 47 | 48 | private: 49 | }; 50 | 51 | #endif -------------------------------------------------------------------------------- /QtTestShader/MyPoint.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MYPOINT_H__ 3 | #define __MYPOINT_H__ 4 | 5 | #include 6 | 7 | namespace CVSystem 8 | { 9 | typedef struct MyPoint 10 | { 11 | public: 12 | float x; 13 | float y; 14 | 15 | MyPoint() 16 | { 17 | this->x = -1; 18 | this->y = -1; 19 | } 20 | 21 | MyPoint(float x, float y) 22 | { 23 | this->x = x; 24 | this->y = y; 25 | } 26 | 27 | bool Invalid() 28 | { 29 | if(((int)x) == -1 && ((int)y) == -1) 30 | return true; 31 | return false; 32 | } 33 | 34 | MyPoint Norm() 35 | { 36 | float vlength = std::sqrt( x * x + y * y ); 37 | return MyPoint(this->x / vlength, this->y / vlength); 38 | } 39 | 40 | float Distance(MyPoint other) 41 | { 42 | float xDist = x - other.x; 43 | float yDist = y - other.y; 44 | return sqrt(xDist * xDist + yDist * yDist); 45 | } 46 | 47 | MyPoint MyPoint::operator+ (const MyPoint& other) { return MyPoint(x + other.x, y + other.y); } 48 | 49 | MyPoint MyPoint::operator- (const MyPoint& other) { return MyPoint(x - other.x, y - other.y); } 50 | 51 | bool MyPoint::operator== (const MyPoint& other) { return ((int)x == (int)other.x && (int)y == (int)other.y); } 52 | 53 | MyPoint MyPoint::operator+= (const MyPoint& other) 54 | { 55 | x += other.x; 56 | y += other.y; 57 | return *this; 58 | } 59 | 60 | MyPoint MyPoint::operator-= (const MyPoint& other) 61 | { 62 | x -= other.x; 63 | y -= other.y; 64 | return *this; 65 | } 66 | 67 | MyPoint MyPoint::operator/ (const float& val) { return MyPoint(x / val, y / val); } 68 | 69 | MyPoint MyPoint::operator* (const float& val) { return MyPoint(x * val, y * val); } 70 | 71 | MyPoint MyPoint::operator*= (const float& val) 72 | { 73 | x *= val; 74 | y *= val; 75 | return *this; 76 | } 77 | 78 | MyPoint MyPoint::operator/= (const float& val) 79 | { 80 | x /= val; 81 | y /= val; 82 | return *this; 83 | } 84 | 85 | double DiagonalLengthSquared() 86 | { 87 | return x * x + y * y; 88 | } 89 | }; 90 | } 91 | #endif -------------------------------------------------------------------------------- /QtTestShader/MyVector3.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MYVECTOR3_H__ 3 | #define __MYVECTOR3_H__ 4 | 5 | #include 6 | 7 | namespace CVSystem 8 | { 9 | typedef struct MyVector3 10 | { 11 | public: 12 | double x; 13 | double y; 14 | double z; 15 | 16 | MyVector3() 17 | { 18 | this->x = -1; 19 | this->y = -1; 20 | this->z = -1; 21 | } 22 | 23 | MyVector3(double x, double y, double z) 24 | { 25 | this->x = x; 26 | this->y = y; 27 | this->z = z; 28 | } 29 | 30 | bool Invalid() 31 | { 32 | if(((int)x) == -1 && ((int)y) == -1 && ((int)z) == -1) 33 | return true; 34 | return false; 35 | } 36 | 37 | MyVector3 Norm() 38 | { 39 | float vlength = std::sqrt(x * x + y * y + z * z); 40 | return MyVector3(this->x / vlength, this->y / vlength, this->z / vlength); 41 | } 42 | 43 | float Distance(MyVector3 other) 44 | { 45 | float xDist = x - other.x; 46 | float yDist = y - other.y; 47 | float zDist = z - other.z; 48 | return sqrt(xDist * xDist + yDist * yDist + zDist * zDist); 49 | } 50 | 51 | MyVector3 MyVector3::operator+ (const MyVector3& other) { return MyVector3(x + other.x, y + other.y, z + other.z); } 52 | 53 | MyVector3 MyVector3::operator- (const MyVector3& other) { return MyVector3(x - other.x, y - other.y, z - other.z); } 54 | 55 | //bool MyVector3::operator== (const MyVector3& other) { return ((int)x == (int)other.x && (int)y == (int)other.y && (int)z == (int)other.z); } 56 | 57 | MyVector3 MyVector3::operator+= (const MyVector3& other) 58 | { 59 | x += other.x; 60 | y += other.y; 61 | z += other.z; 62 | return *this; 63 | } 64 | 65 | MyVector3 MyVector3::operator-= (const MyVector3& other) 66 | { 67 | x -= other.x; 68 | y -= other.y; 69 | z -= other.z; 70 | return *this; 71 | } 72 | 73 | MyVector3 MyVector3::operator/ (const double& val) { return MyVector3(x / val, y / val, z / val); } 74 | 75 | MyVector3 MyVector3::operator* (const double& val) { return MyVector3(x * val, y * val, z / val); } 76 | 77 | /*MyVector3 MyVector3::operator*= (const double& val) 78 | { 79 | x *= val; 80 | y *= val; 81 | z *= val; 82 | return *this; 83 | }*/ 84 | 85 | /*MyVector3 MyVector3::operator/= (const double& val) 86 | { 87 | x /= val; 88 | y /= val; 89 | z /= val; 90 | return *this; 91 | }*/ 92 | }; 93 | } 94 | #endif -------------------------------------------------------------------------------- /QtTestShader/MyVertex.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __VERTEX_H__ 4 | #define __VERTEX_H__ 5 | 6 | #include 7 | #include "MyPoint.h" 8 | 9 | 10 | typedef struct MyVertex 11 | { 12 | public: 13 | CVSystem::MyPoint xyCoor; 14 | 15 | double k; 16 | double l; 17 | double m; 18 | 19 | MyVertex() 20 | { 21 | this->xyCoor.x = -1; 22 | this->xyCoor.y = -1; 23 | 24 | this->k = -1; 25 | this->l = -1; 26 | this->m = -1; 27 | } 28 | 29 | MyVertex(float x, float y, double k, double l, double m) 30 | { 31 | this->xyCoor.x = x; 32 | this->xyCoor.y = y; 33 | 34 | this->k = k; 35 | this->l = l; 36 | this->m = m; 37 | } 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "QtTestShader.h" 3 | 4 | QtTestShader::QtTestShader(QWidget *parent) 5 | : QMainWindow(parent) 6 | { 7 | ui.setupUi(this); 8 | 9 | QGLFormat glFormat; 10 | glFormat.setVersion(2, 0); 11 | glFormat.setProfile(QGLFormat::CompatibilityProfile); 12 | //glFormat.setProfile( QGLFormat::CoreProfile ); 13 | glFormat.setSampleBuffers( true ); 14 | 15 | myGridLayout = new QGridLayout(ui.centralWidget); 16 | myGLWidget = new GLWidget(glFormat, ui.centralWidget); 17 | 18 | myGridLayout->setSpacing(6); 19 | myGridLayout->setContentsMargins(11, 11, 11, 11); 20 | myGridLayout->setObjectName(QStringLiteral("gridLayout")); 21 | myGLWidget->setObjectName(QStringLiteral("widget")); 22 | 23 | myGridLayout->addWidget(myGLWidget, 0, 0, 1, 1); 24 | 25 | // timer 26 | QTimer *timer = new QTimer(this); 27 | connect(timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); 28 | timer->start(100); 29 | } 30 | 31 | QtTestShader::~QtTestShader() 32 | { 33 | } 34 | 35 | void QtTestShader::UpdateTimer() 36 | { 37 | //std::cout << "update\n"; 38 | int cType = myGLWidget->GetCurveType(); 39 | 40 | /* 41 | CURVE_TYPE_UNKNOWN = 0, 42 | CURVE_TYPE_SERPENTINE, 43 | CURVE_TYPE_LOOP, 44 | CURVE_TYPE_CUSP_WITH_INFLECTION_AT_INFINITY, 45 | CURVE_TYPE_CUPS_WITH_CUPS_AT_INFINITY, 46 | CURVE_TYPE_QUADRATIC, 47 | CURVE_TYPE_LINE, 48 | */ 49 | 50 | QString str = "CURVE_TYPE_UNKNOWN"; 51 | 52 | if(cType == 1) str = "CURVE_TYPE_SERPENTINE"; 53 | else if(cType == 2) str = "CURVE_TYPE_LOOP"; 54 | else if(cType == 3) str = "CURVE_TYPE_CUSP"; 55 | else if(cType == 4) str = "CURVE_TYPE_QUADRATIC"; 56 | else if(cType == 5) str = "CURVE_TYPE_LINE"; 57 | 58 | ui.statusBar->showMessage(str, 100); 59 | } 60 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.h: -------------------------------------------------------------------------------- 1 | #ifndef QTTESTSHADER_H 2 | #define QTTESTSHADER_H 3 | 4 | #include 5 | #include "ui_QtTestShader.h" 6 | #include "GLWidget.h" 7 | 8 | class QtTestShader : public QMainWindow 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | QtTestShader(QWidget *parent = 0); 14 | ~QtTestShader(); 15 | 16 | private: 17 | Ui::QtTestShaderClass ui; 18 | 19 | QGridLayout *myGridLayout; 20 | GLWidget *myGLWidget; 21 | 22 | private slots: 23 | void UpdateTimer(); 24 | }; 25 | 26 | #endif // QTTESTSHADER_H 27 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azer89/GPU_Curve_Rendering/41380a44110256ca210b37de38239ac2d1f9070f/QtTestShader/QtTestShader.ico -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "QtTestShader.ico" 2 | 3 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QtTestShaderClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1024 10 | 768 11 | 12 | 13 | 14 | QtTestShader 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {B12702AD-ABFB-343A-A199-8E24837244A3} 15 | Qt4VSv1.0 16 | 17 | 18 | 19 | Application 20 | v100 21 | 22 | 23 | Application 24 | v110 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | <_ProjectFileVersion>11.0.60610.1 38 | 39 | 40 | $(SolutionDir)$(Platform)\$(Configuration)\ 41 | 42 | 43 | $(SolutionDir)$(Platform)\$(Configuration)\ 44 | 45 | 46 | 47 | UNICODE;WIN32;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) 48 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtQml;$(QTDIR)\include\QtQuick;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;D:\VG_Project\Eigen_3_2;D:\VG_Project\boost_1_53_0;%(AdditionalIncludeDirectories) 49 | Disabled 50 | ProgramDatabase 51 | MultiThreadedDebugDLL 52 | false 53 | Use 54 | stdafx.h 55 | $(IntDir)$(TargetName).pch 56 | 57 | 58 | Console 59 | $(OutDir)\$(ProjectName).exe 60 | $(QTDIR)\lib;..\Debug;%(AdditionalLibraryDirectories) 61 | true 62 | qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Qmld.lib;Qt5Quickd.lib;Qt5OpenGLd.lib;Qt5Svgd.lib;Qt5Widgetsd.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) 63 | 64 | 65 | 66 | 67 | UNICODE;WIN32;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) 68 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) 69 | 70 | MultiThreadedDLL 71 | false 72 | Use 73 | stdafx.h 74 | $(IntDir)$(TargetName).pch 75 | 76 | 77 | Windows 78 | $(OutDir)\$(ProjectName).exe 79 | $(QTDIR)\lib;%(AdditionalLibraryDirectories) 80 | false 81 | qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5OpenGL.lib;opengl32.lib;glu32.lib;Qt5Widgets.lib;%(AdditionalDependencies) 82 | 83 | 84 | 85 | 86 | true 87 | 88 | 89 | true 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | true 99 | 100 | 101 | true 102 | 103 | 104 | 105 | 106 | 107 | Create 108 | Create 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | $(QTDIR)\bin\moc.exe;%(FullPath) 131 | Moc%27ing GLWidget.h... 132 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 133 | "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtSvg" "-I$(QTDIR)\include\QtWidgets" "-ID:\VG_Project\Eigen_3_2" "-ID:\VG_Project\boost_1_53_0" "-fstdafx.h" "-f../../GLWidget.h" 134 | $(QTDIR)\bin\moc.exe;%(FullPath) 135 | Moc%27ing GLWidget.h... 136 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 137 | "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../GLWidget.h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" 138 | 139 | 140 | $(QTDIR)\bin\moc.exe;%(FullPath) 141 | Moc%27ing QtTestShader.h... 142 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 143 | "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtSvg" "-I$(QTDIR)\include\QtWidgets" "-ID:\VG_Project\Eigen_3_2" "-ID:\VG_Project\boost_1_53_0" "-fstdafx.h" "-f../../QtTestShader.h" 144 | $(QTDIR)\bin\moc.exe;%(FullPath) 145 | Moc%27ing QtTestShader.h... 146 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 147 | "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../QtTestShader.h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | $(QTDIR)\bin\uic.exe;%(AdditionalInputs) 156 | Uic%27ing %(Identity)... 157 | .\GeneratedFiles\ui_%(Filename).h;%(Outputs) 158 | "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" 159 | $(QTDIR)\bin\uic.exe;%(AdditionalInputs) 160 | Uic%27ing %(Identity)... 161 | .\GeneratedFiles\ui_%(Filename).h;%(Outputs) 162 | "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" 163 | 164 | 165 | 166 | 167 | %(FullPath);%(AdditionalInputs) 168 | Rcc%27ing %(Identity)... 169 | .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) 170 | "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp 171 | %(FullPath);%(AdditionalInputs) 172 | Rcc%27ing %(Identity)... 173 | .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) 174 | "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;cxx;c;def 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h 11 | 12 | 13 | {99349809-55BA-4b9d-BF79-8FDBB0286EB3} 14 | ui 15 | 16 | 17 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 18 | qrc;* 19 | false 20 | 21 | 22 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 23 | moc;h;cpp 24 | False 25 | 26 | 27 | {3ef705ad-83d2-4fb3-ab27-ef6621ece4ee} 28 | cpp;moc 29 | False 30 | 31 | 32 | {4ac82a09-9a40-4231-a355-b5d0dea54bb5} 33 | cpp;moc 34 | False 35 | 36 | 37 | {14bf384e-2edc-453f-9b6b-431743e55011} 38 | 39 | 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Generated Files\Debug 52 | 53 | 54 | Generated Files\Release 55 | 56 | 57 | Generated Files 58 | 59 | 60 | Generated Files\Debug 61 | 62 | 63 | Generated Files\Release 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | 73 | 74 | Header Files 75 | 76 | 77 | Generated Files 78 | 79 | 80 | Header Files 81 | 82 | 83 | Header Files 84 | 85 | 86 | Header Files 87 | 88 | 89 | 90 | 91 | Header Files 92 | 93 | 94 | Form Files 95 | 96 | 97 | Resource Files 98 | 99 | 100 | Header Files 101 | 102 | 103 | Header Files 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | Shaders 112 | 113 | 114 | Shaders 115 | 116 | 117 | Shaders 118 | 119 | 120 | -------------------------------------------------------------------------------- /QtTestShader/QtTestShader.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | C:\Qt\Qt5.1.0\5.1.0\msvc2010_opengl 6 | PATH=$(QTDIR)\bin%3b$(PATH) 7 | 8 | 9 | C:\Qt\Qt5.1.0\5.1.0\msvc2010_opengl 10 | PATH=$(QTDIR)\bin%3b$(PATH) 11 | 12 | -------------------------------------------------------------------------------- /QtTestShader/Quad.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | // convex or concave (not yet implemented) 4 | uniform int flag; 5 | 6 | void main(void) 7 | { 8 | vec2 p = gl_TexCoord[0].st; 9 | 10 | if( (p.s * p.s - p.t) > 0.0 ) 11 | discard; 12 | 13 | gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /QtTestShader/VertexShader.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform mat4 mat; 4 | in vec4 vertex; 5 | 6 | void main(void) 7 | { 8 | gl_Position = vertex * mat; 9 | gl_TexCoord[0] = gl_MultiTexCoord0; 10 | } -------------------------------------------------------------------------------- /QtTestShader/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "QtTestShader.h" 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | QtTestShader w; 9 | w.show(); 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /QtTestShader/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /QtTestShader/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define _USE_MATH_DEFINES 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | 46 | #ifndef M_EPS 47 | #define M_EPS 1e-8 48 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![alt tag](https://raw.githubusercontent.com/azer89/GPU_Curve_Rendering/master/bezier_large.png) 2 | 3 | An implementation of a SIGGRAPH paper:
4 | Resolution Independent Curve Rendering using Programmable Graphics Hardware (SIGGRAPH 2005)
5 | by Charles Loop and Jim Blinn
6 | http://dx.doi.org/10.1145/1073204.1073303
7 | 8 | You can take a look on [CurveRenderer.cpp](https://github.com/azer89/GPU_Curve_Rendering/blob/master/QtTestShader/CurveRenderer.cpp) where the actual algorithm is implemented. 9 | 10 | This repo was actually a small part of a bigger project about vectorizing rasterized manga artwork. Below is the video demo: 11 | 12 | https://github.com/azer89/GPU_Curve_Rendering/assets/790432/6ef8e14e-4adc-470d-8dd7-3b47f6bafe4e 13 | 14 | Dependencies:
15 | 1. Qt 5.x and OpenGL
16 | 2. Visual Studio 2010
17 | 3. [Eigen Matrix Library](http://eigen.tuxfamily.org)
18 | -------------------------------------------------------------------------------- /bezier_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azer89/GPU_Curve_Rendering/41380a44110256ca210b37de38239ac2d1f9070f/bezier_large.png --------------------------------------------------------------------------------