├── AccessObj.cpp ├── AccessObj.h ├── BasicStructure.h ├── Camera.cpp ├── Camera.h ├── Mat.h ├── Mat.inl ├── MathDefs.h ├── Point3D.cpp ├── Point3D.h ├── README ├── RenderState.cpp ├── RenderState.h ├── ScanLine.cpp ├── ScanLine.h ├── Vec.h ├── VectOps.cpp ├── VectOps.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── sdi.qrc ├── zbuffer_qt.pri ├── zbuffer_qt.pro └── zbuffer_qt.vcproj /AccessObj.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 10 | 11 | using namespace std; 12 | 13 | #ifndef SAFE_DELETE 14 | #define SAFE_DELETE(p) if(p) { delete (p); (p)=0; } 15 | #endif 16 | 17 | #ifndef SAFE_DELETE_ARRAY 18 | #define SAFE_DELETE_ARRAY(p) if(p) { delete[] (p); (p)=0; } 19 | #endif 20 | 21 | 22 | ////////////////////////////////////////////////////////////////////// 23 | 24 | #include "AccessObj.h" 25 | 26 | ////////////////////////////////////////////////////////////////////// 27 | // Construction/Destruction 28 | ////////////////////////////////////////////////////////////////////// 29 | CAccessObj::CAccessObj() 30 | { 31 | m_pModel = NULL; 32 | } 33 | 34 | CAccessObj::~CAccessObj() 35 | { 36 | Destory(); 37 | } 38 | 39 | ////////////////////////////////////////////////////////////////////// 40 | // Equal: compares two vectors and returns true if they are 41 | // equal (within a certain threshold) or false if not. An epsilon 42 | // that works fairly well is 0.000001. 43 | // 44 | // u - array of 3 GLfloats (float u[3]) 45 | // v - array of 3 GLfloats (float v[3]) 46 | ////////////////////////////////////////////////////////////////////// 47 | bool CAccessObj::Equal(CPoint3D * u, CPoint3D * v, float epsilon) 48 | { 49 | if (objAbs(u->x - v->x) < epsilon && 50 | objAbs(u->y - v->y) < epsilon && 51 | objAbs(u->z - v->z) < epsilon) 52 | { 53 | return true; 54 | } 55 | return false; 56 | } 57 | 58 | 59 | ////////////////////////////////////////////////////////////////////// 60 | // FindGroup: Find a group in the model 61 | ////////////////////////////////////////////////////////////////////// 62 | COBJgroup * CAccessObj::FindGroup(char* name) 63 | { 64 | COBJgroup * group; 65 | 66 | assert(m_pModel); 67 | 68 | group = m_pModel->pGroups; 69 | while(group) 70 | { 71 | if (!strcmp(name, group->name)) 72 | break; 73 | group = group->next; 74 | } 75 | 76 | return group; 77 | } 78 | 79 | ////////////////////////////////////////////////////////////////////// 80 | // AddGroup: Add a group to the model 81 | ////////////////////////////////////////////////////////////////////// 82 | COBJgroup * CAccessObj::AddGroup(char* name) 83 | { 84 | COBJgroup* group; 85 | 86 | group = FindGroup(name); 87 | if (!group) 88 | { 89 | group = new COBJgroup; 90 | sprintf_s(group->name, 256, "%s", name); 91 | group->nTriangles = 0; 92 | group->pTriangles = NULL; 93 | group->next = m_pModel->pGroups; 94 | m_pModel->pGroups = group; 95 | m_pModel->nGroups++; 96 | } 97 | 98 | return group; 99 | } 100 | 101 | ////////////////////////////////////////////////////////////////////// 102 | // DirName: return the directory given a path 103 | // 104 | // path - filesystem path 105 | // 106 | // NOTE: the return value should be free'd. 107 | ////////////////////////////////////////////////////////////////////// 108 | char * CAccessObj::DirName(char* path) 109 | { 110 | static char dir[256]; 111 | char *s; 112 | 113 | sprintf_s(dir,256, "%s", path); 114 | 115 | s = strrchr(dir, '\\'); 116 | if (s) s[1] = '\0'; 117 | else dir[0] = '\0'; 118 | 119 | return dir; 120 | } 121 | 122 | ////////////////////////////////////////////////////////////////////// 123 | // FirstPass: first pass at a Wavefront OBJ file that gets all the 124 | // statistics of the model (such as #vertices, #normals, etc) 125 | // 126 | // model - properly initialized COBJmodel structure 127 | // file - (fopen'd) file descriptor 128 | ////////////////////////////////////////////////////////////////////// 129 | bool CAccessObj::FirstPass(FILE* file) 130 | { 131 | unsigned int nVertices; /* number of vertices in m_pModel */ 132 | unsigned int nNormals; /* number of normals in m_pModel */ 133 | unsigned int nTexCoords; /* number of texcoords in m_pModel */ 134 | unsigned int nTriangles; /* number of triangles in m_pModel */ 135 | COBJgroup* group; /* current group */ 136 | unsigned v, n, t; 137 | char buf[129]; 138 | 139 | /* make a default group */ 140 | group = AddGroup("default"); 141 | 142 | nVertices = nNormals = nTexCoords = nTriangles = 0; 143 | while(fscanf(file, "%128s", buf, 129) != EOF) 144 | { 145 | switch(buf[0]) 146 | { 147 | case '#': /* comment */ 148 | /* eat up rest of line */ 149 | fgets(buf, sizeof(buf), file); 150 | break; 151 | case 'v': /* v, vn, vt */ 152 | switch(buf[1]) 153 | { 154 | case '\0': /* vertex */ 155 | /* eat up rest of line */ 156 | fgets(buf, sizeof(buf), file); 157 | nVertices++; 158 | break; 159 | case 'n': /* normal */ 160 | /* eat up rest of line */ 161 | fgets(buf, sizeof(buf), file); 162 | nNormals++; 163 | break; 164 | case 't': /* texcoord */ 165 | /* eat up rest of line */ 166 | fgets(buf, sizeof(buf), file); 167 | nTexCoords++; 168 | break; 169 | default: 170 | printf("FirstPass(): Unknown token \"%s\".\n", buf); 171 | exit(1); 172 | break; 173 | } 174 | break; 175 | 176 | case 'u': 177 | /* eat up rest of line */ 178 | fgets(buf, sizeof(buf), file); 179 | break; 180 | case 'g': /* group */ 181 | /* eat up rest of line */ 182 | fgets(buf, sizeof(buf), file); 183 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 184 | group = AddGroup(buf); 185 | break; 186 | case 'f': /* face */ 187 | v = n = t = 0; 188 | fscanf(file, "%128s", buf, 129); 189 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 190 | if (strstr(buf, "//")) 191 | { 192 | /* v//n */ 193 | sscanf(buf, "%d//%d", &v, &n); 194 | fscanf(file, "%d//%d", &v, &n); 195 | fscanf(file, "%d//%d", &v, &n); 196 | nTriangles++; 197 | group->nTriangles++; 198 | while(fscanf(file, "%d//%d", &v, &n) > 0) 199 | { 200 | nTriangles++; 201 | group->nTriangles++; 202 | } 203 | } 204 | else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) 205 | { 206 | /* v/t/n */ 207 | fscanf(file, "%d/%d/%d", &v, &t, &n); 208 | fscanf(file, "%d/%d/%d", &v, &t, &n); 209 | nTriangles++; 210 | group->nTriangles++; 211 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) 212 | { 213 | nTriangles++; 214 | group->nTriangles++; 215 | } 216 | } 217 | else if (sscanf(buf, "%d/%d", &v, &t) == 2) 218 | { 219 | /* v/t */ 220 | fscanf(file, "%d/%d", &v, &t); 221 | fscanf(file, "%d/%d", &v, &t); 222 | nTriangles++; 223 | group->nTriangles++; 224 | while(fscanf(file, "%d/%d", &v, &t) > 0) 225 | { 226 | nTriangles++; 227 | group->nTriangles++; 228 | } 229 | } 230 | else 231 | { 232 | /* v */ 233 | fscanf(file, "%d", &v); 234 | fscanf(file, "%d", &v); 235 | nTriangles++; 236 | group->nTriangles++; 237 | while(fscanf(file, "%d", &v) > 0) 238 | { 239 | nTriangles++; 240 | group->nTriangles++; 241 | } 242 | } 243 | break; 244 | 245 | default: 246 | /* eat up rest of line */ 247 | if (isalpha(buf[0])) 248 | { 249 | fgets(buf, sizeof(buf), file); 250 | } 251 | else 252 | return false; 253 | break; 254 | } 255 | } 256 | 257 | /* set the stats in the m_pModel structure */ 258 | m_pModel->nVertices = nVertices; 259 | m_pModel->nNormals = nNormals; 260 | m_pModel->nTriangles = nTriangles; 261 | 262 | /* allocate memory for the triangles in each group */ 263 | group = m_pModel->pGroups; 264 | while(group) 265 | { 266 | if (group->nTriangles > 0) 267 | group->pTriangles = new unsigned int [group->nTriangles]; 268 | group->nTriangles = 0; 269 | group = group->next; 270 | } 271 | return true; 272 | } 273 | 274 | ////////////////////////////////////////////////////////////////////// 275 | // SecondPass: second pass at a Wavefront OBJ file that gets all 276 | // the data. 277 | // 278 | // model - properly initialized COBJmodel structure 279 | // file - (fopen'd) file descriptor 280 | ////////////////////////////////////////////////////////////////////// 281 | void CAccessObj::SecondPass(FILE* file) 282 | { 283 | unsigned int nVertices; /* number of vertices in m_pModel */ 284 | unsigned int nNormals; /* number of normals in m_pModel */ 285 | unsigned int nTriangles; /* number of triangles in m_pModel */ 286 | CPoint3D * vertices; /* array of vertices */ 287 | CPoint3D * normals; /* array of normals */ 288 | COBJgroup * group; /* current group pointer */ 289 | unsigned int v, n, t; 290 | char buf[128]; 291 | 292 | /* set the pointer shortcuts */ 293 | vertices = m_pModel->vpVertices; 294 | normals = m_pModel->vpNormals; 295 | group = m_pModel->pGroups; 296 | 297 | /* on the second pass through the file, read all the data into the 298 | allocated arrays */ 299 | nVertices = nNormals = 1; 300 | nTriangles = 0; 301 | 302 | int nNormalAdd = 0; 303 | int nNormalCount = 0; 304 | 305 | while(fscanf(file, "%s", buf) != EOF) 306 | { 307 | switch(buf[0]) 308 | { 309 | case '#': /* comment */ 310 | /* eat up rest of line */ 311 | fgets(buf, sizeof(buf), file); 312 | break; 313 | case 'v': /* v, vn, vt */ 314 | switch(buf[1]) 315 | { 316 | case '\0': /* vertex */ 317 | fscanf(file, "%f %f %f", 318 | &vertices[nVertices].x, 319 | &vertices[nVertices].y, 320 | &vertices[nVertices].z); 321 | nVertices++; 322 | break; 323 | case 'n': /* normal */ 324 | fscanf(file, "%f %f %f", 325 | &normals[nNormals].x, 326 | &normals[nNormals].y, 327 | &normals[nNormals].z); 328 | nNormals++; 329 | nNormalCount ++; 330 | break; 331 | } 332 | break; 333 | 334 | case 'g': /* group */ 335 | /* eat up rest of line */ 336 | fgets(buf, sizeof(buf), file); 337 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 338 | group = FindGroup(buf); 339 | nNormalAdd += nNormalCount; 340 | nNormalCount = 0; 341 | break; 342 | case 'f': /* face */ 343 | v = n = t = 0; 344 | fscanf(file, "%s", buf); 345 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 346 | if (strstr(buf, "//")) 347 | { 348 | /* v//n */ 349 | sscanf(buf, "%d//%d", &v, &n); 350 | Tri(nTriangles).vindices[0] = v; 351 | Tri(nTriangles).nindices[0] = n;// + nNormalAdd; 352 | fscanf(file, "%d//%d", &v, &n); 353 | Tri(nTriangles).vindices[1] = v; 354 | Tri(nTriangles).nindices[1] = n;// + nNormalAdd; 355 | fscanf(file, "%d//%d", &v, &n); 356 | Tri(nTriangles).vindices[2] = v; 357 | Tri(nTriangles).nindices[2] = n;// + nNormalAdd; 358 | group->pTriangles[group->nTriangles++] = nTriangles; 359 | nTriangles++; 360 | while(fscanf(file, "%d//%d", &v, &n) > 0) 361 | { 362 | Tri(nTriangles).vindices[0] = Tri(nTriangles-1).vindices[0]; 363 | Tri(nTriangles).nindices[0] = Tri(nTriangles-1).nindices[0]; 364 | Tri(nTriangles).vindices[1] = Tri(nTriangles-1).vindices[2]; 365 | Tri(nTriangles).nindices[1] = Tri(nTriangles-1).nindices[2]; 366 | Tri(nTriangles).vindices[2] = v; 367 | Tri(nTriangles).nindices[2] = n;// + nNormalAdd; 368 | group->pTriangles[group->nTriangles++] = nTriangles; 369 | nTriangles++; 370 | } 371 | } 372 | else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) 373 | { 374 | /* v/t/n */ 375 | Tri(nTriangles).vindices[0] = v; 376 | Tri(nTriangles).nindices[0] = n;// + nNormalAdd; 377 | fscanf(file, "%d/%d/%d", &v, &t, &n); 378 | Tri(nTriangles).vindices[1] = v; 379 | Tri(nTriangles).nindices[1] = n;// + nNormalAdd; 380 | fscanf(file, "%d/%d/%d", &v, &t, &n); 381 | Tri(nTriangles).vindices[2] = v; 382 | Tri(nTriangles).nindices[2] = n;// + nNormalAdd; 383 | group->pTriangles[group->nTriangles++] = nTriangles; 384 | nTriangles++; 385 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) 386 | { 387 | Tri(nTriangles).vindices[0] = Tri(nTriangles-1).vindices[0]; 388 | Tri(nTriangles).nindices[0] = Tri(nTriangles-1).nindices[0]; 389 | Tri(nTriangles).vindices[1] = Tri(nTriangles-1).vindices[2]; 390 | Tri(nTriangles).nindices[1] = Tri(nTriangles-1).nindices[2]; 391 | Tri(nTriangles).vindices[2] = v; 392 | Tri(nTriangles).nindices[2] = n;// + nNormalAdd; 393 | group->pTriangles[group->nTriangles++] = nTriangles; 394 | nTriangles++; 395 | } 396 | } 397 | else if (sscanf(buf, "%d/%d", &v, &t) == 2) 398 | { 399 | /* v/t */ 400 | Tri(nTriangles).vindices[0] = v; 401 | fscanf(file, "%d/%d", &v, &t); 402 | Tri(nTriangles).vindices[1] = v; 403 | fscanf(file, "%d/%d", &v, &t); 404 | Tri(nTriangles).vindices[2] = v; 405 | group->pTriangles[group->nTriangles++] = nTriangles; 406 | nTriangles++; 407 | while(fscanf(file, "%d/%d", &v, &t) > 0) 408 | { 409 | Tri(nTriangles).vindices[0] = Tri(nTriangles-1).vindices[0]; 410 | Tri(nTriangles).vindices[1] = Tri(nTriangles-1).vindices[2]; 411 | Tri(nTriangles).vindices[2] = v; 412 | group->pTriangles[group->nTriangles++] = nTriangles; 413 | nTriangles++; 414 | } 415 | } 416 | else 417 | { 418 | /* v */ 419 | sscanf(buf, "%d", &v); 420 | Tri(nTriangles).vindices[0] = v; 421 | fscanf(file, "%d", &v); 422 | Tri(nTriangles).vindices[1] = v; 423 | fscanf(file, "%d", &v); 424 | Tri(nTriangles).vindices[2] = v; 425 | group->pTriangles[group->nTriangles++] = nTriangles; 426 | nTriangles++; 427 | while(fscanf(file, "%d", &v) > 0) 428 | { 429 | Tri(nTriangles).vindices[0] = Tri(nTriangles-1).vindices[0]; 430 | Tri(nTriangles).vindices[1] = Tri(nTriangles-1).vindices[2]; 431 | Tri(nTriangles).vindices[2] = v; 432 | group->pTriangles[group->nTriangles++] = nTriangles; 433 | nTriangles++; 434 | } 435 | } 436 | break; 437 | 438 | default: 439 | /* eat up rest of line */ 440 | fgets(buf, sizeof(buf), file); 441 | break; 442 | } 443 | } 444 | } 445 | 446 | ////////////////////////////////////////////////////////////////////// 447 | // Dimensions: Calculates the dimensions (width, height, depth) of 448 | // a model. 449 | // 450 | // model - initialized COBJmodel structure 451 | // dimensions - array of 3 GLfloats (float dimensions[3]) 452 | ////////////////////////////////////////////////////////////////////// 453 | void CAccessObj::Dimensions(float* dimensions) 454 | { 455 | unsigned int i; 456 | CPoint3D vMax, vMin; 457 | 458 | assert(m_pModel); 459 | assert(m_pModel->vpVertices); 460 | assert(dimensions); 461 | 462 | /* get the max/mins */ 463 | vMax = vMin = m_pModel->vpVertices[0]; 464 | for (i = 1; i <= m_pModel->nVertices; i++) 465 | { 466 | if (vMax.x < m_pModel->vpVertices[i].x) 467 | vMax.x = m_pModel->vpVertices[i].x; 468 | if (vMin.x > m_pModel->vpVertices[i].x) 469 | vMin.x = m_pModel->vpVertices[i].x; 470 | 471 | if (vMax.y < m_pModel->vpVertices[i].y) 472 | vMax.y = m_pModel->vpVertices[i].y; 473 | if (vMin.y > m_pModel->vpVertices[i].y) 474 | vMin.y = m_pModel->vpVertices[i].y; 475 | 476 | if (vMax.z < m_pModel->vpVertices[i].z) 477 | vMax.z = m_pModel->vpVertices[i].z; 478 | if (vMin.z > m_pModel->vpVertices[i].z) 479 | vMin.z = m_pModel->vpVertices[i].z; 480 | } 481 | 482 | /* calculate m_pModel width, height, and depth */ 483 | dimensions[0] = vMax.x-vMin.x; 484 | dimensions[1] = vMax.y-vMin.y; 485 | dimensions[2] = vMax.z-vMin.z; 486 | } 487 | 488 | ////////////////////////////////////////////////////////////////////// 489 | // Scale: Scales a model by a given amount. 490 | // 491 | // model - properly initialized COBJmodel structure 492 | // scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 493 | ////////////////////////////////////////////////////////////////////// 494 | void CAccessObj::Scale(float scale) 495 | { 496 | unsigned int i; 497 | 498 | for (i = 1; i <= m_pModel->nVertices; i++) 499 | m_pModel->vpVertices[i] = m_pModel->vpVertices[i] * scale; 500 | } 501 | 502 | ////////////////////////////////////////////////////////////////////// 503 | // ReverseWinding: Reverse the polygon winding for all polygons in 504 | // this model. Default winding is counter-clockwise. Also changes 505 | // the direction of the normals. 506 | // 507 | // model - properly initialized COBJmodel structure 508 | ////////////////////////////////////////////////////////////////////// 509 | void CAccessObj::ReverseWinding() 510 | { 511 | unsigned int i, swap; 512 | 513 | assert(m_pModel); 514 | 515 | for (i = 0; i < m_pModel->nTriangles; i++) 516 | { 517 | swap = Tri(i).vindices[0]; 518 | Tri(i).vindices[0] = Tri(i).vindices[2]; 519 | Tri(i).vindices[2] = swap; 520 | 521 | if (m_pModel->nNormals) 522 | { 523 | swap = Tri(i).nindices[0]; 524 | Tri(i).nindices[0] = Tri(i).nindices[2]; 525 | Tri(i).nindices[2] = swap; 526 | } 527 | } 528 | 529 | /* reverse facet normals */ 530 | for (i = 1; i <= m_pModel->nFacetnorms; i++) 531 | m_pModel->vpFacetNorms[i] = m_pModel->vpFacetNorms[i]*(-1); 532 | 533 | /* reverse vertex normals */ 534 | for (i = 1; i <= m_pModel->nNormals; i++) 535 | m_pModel->vpNormals[i] = m_pModel->vpNormals[i]*(-1); 536 | } 537 | 538 | ////////////////////////////////////////////////////////////////////// 539 | // FacetNormals: Generates facet normals for a model (by taking the 540 | // cross product of the two vectors derived from the sides of each 541 | // triangle). Assumes a counter-clockwise winding. 542 | // 543 | // model - initialized COBJmodel structure 544 | ////////////////////////////////////////////////////////////////////// 545 | void CAccessObj::FacetNormals() 546 | { 547 | unsigned int i; 548 | CPoint3D u, v; 549 | 550 | assert(m_pModel); 551 | assert(m_pModel->vpVertices); 552 | 553 | /* clobber any old facetnormals */ 554 | SAFE_DELETE_ARRAY(m_pModel->vpFacetNorms); 555 | 556 | /* allocate memory for the new facet normals */ 557 | m_pModel->nFacetnorms = m_pModel->nTriangles; 558 | m_pModel->vpFacetNorms = new CPoint3D [m_pModel->nFacetnorms + 1]; 559 | 560 | for (i = 0; i < m_pModel->nTriangles; i++) 561 | { 562 | m_pModel->pTriangles[i].findex = i+1; 563 | 564 | u = m_pModel->vpVertices[Tri(i).vindices[1]] - m_pModel->vpVertices[Tri(i).vindices[0]]; 565 | v = m_pModel->vpVertices[Tri(i).vindices[2]] - m_pModel->vpVertices[Tri(i).vindices[0]]; 566 | 567 | m_pModel->vpFacetNorms[i+1] = u * v; 568 | m_pModel->vpFacetNorms[i+1].unify(); 569 | } 570 | } 571 | 572 | ////////////////////////////////////////////////////////////////////// 573 | // VertexNormals: Generates smooth vertex normals for a model. 574 | // First builds a list of all the triangles each vertex is in. Then 575 | // loops through each vertex in the the list averaging all the facet 576 | // normals of the triangles each vertex is in. Finally, sets the 577 | // normal index in the triangle for the vertex to the generated smooth 578 | // normal. If the dot product of a facet normal and the facet normal 579 | // associated with the first triangle in the list of triangles the 580 | // current vertex is in is greater than the cosine of the angle 581 | // parameter to the function, that facet normal is not added into the 582 | // average normal calculation and the corresponding vertex is given 583 | // the facet normal. This tends to preserve hard edges. The angle to 584 | // use depends on the model, but 90 degrees is usually a good start. 585 | // 586 | // model - initialized COBJmodel structure 587 | // angle - maximum angle (in degrees) to smooth across 588 | ////////////////////////////////////////////////////////////////////// 589 | void CAccessObj::VertexNormals(float angle) 590 | { 591 | OBJnode* node; 592 | typedef list NodeList; 593 | typedef NodeList::iterator NodeListItor; 594 | typedef vector ListArray; 595 | typedef ListArray::iterator ListArrItor; 596 | ListArray members; 597 | CPoint3D * normals; 598 | unsigned int nNormals; 599 | CPoint3D t_vAverage; 600 | float dot, cos_angle; 601 | unsigned int i; 602 | 603 | assert(m_pModel); 604 | assert(m_pModel->vpFacetNorms); 605 | 606 | /* calculate the cosine of the angle (in degrees) */ 607 | cos_angle = (float)cos(angle * 3.14159265 / 180.0); 608 | 609 | /* nuke any previous normals */ 610 | SAFE_DELETE_ARRAY(m_pModel->vpNormals); 611 | 612 | /* allocate space for new normals */ 613 | m_pModel->nNormals = m_pModel->nTriangles * 3; /* 3 normals per triangle */ 614 | m_pModel->vpNormals = new CPoint3D [m_pModel->nNormals+1]; 615 | 616 | /* allocate a structure that will hold a linked list of triangle 617 | indices for each vertex */ 618 | members.resize(m_pModel->nVertices + 1); 619 | 620 | /* for every triangle, create a node for each vertex in it */ 621 | for (i = 0; i < m_pModel->nTriangles; i++) 622 | { 623 | node = new OBJnode; 624 | node->triIdx = i; 625 | node->index = 0; 626 | members[Tri(i).vindices[0]].push_back(node); 627 | node = new OBJnode; 628 | node->triIdx = i; 629 | node->index = 1; 630 | members[Tri(i).vindices[1]].push_back(node); 631 | node = new OBJnode; 632 | node->triIdx = i; 633 | node->index = 2; 634 | members[Tri(i).vindices[2]].push_back(node); 635 | } 636 | 637 | /* calculate the average normal for each vertex */ 638 | nNormals = 1; 639 | for (i = 1; i <= m_pModel->nVertices; i++) 640 | { 641 | if (members[i].empty()) 642 | { 643 | continue; 644 | #ifdef _DEBUG 645 | //fprintf(stderr, "VertexNormals(): vertex w/o a triangle\n"); 646 | #endif // _DEBUG 647 | } 648 | 649 | // calculate an average normal for this vertex by averaging the 650 | // facet normal of every triangle this vertex is in 651 | NodeListItor itl = members[i].begin(); 652 | NodeListItor itl_end = members[i].end(); 653 | 654 | for (; itl!=itl_end; ++itl) 655 | { 656 | /* only average if the dot product of the angle between the two 657 | facet normals is greater than the cosine of the threshold 658 | angle -- or, said another way, the angle between the two 659 | facet normals is less than (or equal to) the threshold angle */ 660 | node = *itl; 661 | t_vAverage = CPoint3D(0, 0, 0); 662 | NodeListItor itl_t = members[i].begin(); 663 | for (; itl_t!=itl_end; ++itl_t) 664 | { 665 | OBJnode* node_t = *itl_t; 666 | dot = m_pModel->vpFacetNorms[Tri(node->triIdx).findex] & 667 | m_pModel->vpFacetNorms[Tri(node_t->triIdx).findex]; 668 | if (dot > cos_angle) 669 | { 670 | t_vAverage += m_pModel->vpFacetNorms[Tri(node_t->triIdx).findex]; 671 | /* we averaged at least one normal! */ 672 | } 673 | } 674 | /* normalize the averaged normal */ 675 | t_vAverage.unify(); 676 | 677 | /* add the normal to the vertex normals list */ 678 | m_pModel->vpNormals[nNormals] = t_vAverage; 679 | Tri(node->triIdx).nindices[node->index] = nNormals; 680 | ++nNormals; 681 | } 682 | } 683 | 684 | /* free the member information */ 685 | ListArrItor ita = members.begin(); 686 | ListArrItor ita_end = members.end(); 687 | for (; ita!=ita_end; ++ita) 688 | { 689 | NodeListItor itl = ita->begin(); 690 | NodeListItor itl_end = ita->end(); 691 | for (; itl!=itl_end; ++itl) 692 | { 693 | SAFE_DELETE(*itl); 694 | } 695 | } 696 | } 697 | 698 | 699 | ////////////////////////////////////////////////////////////////////// 700 | // objDelete: Deletes a COBJmodel structure. 701 | // 702 | // model - initialized COBJmodel structure 703 | ////////////////////////////////////////////////////////////////////// 704 | void CAccessObj::Destory() 705 | { 706 | delete m_pModel; 707 | m_pModel = NULL; 708 | } 709 | 710 | ////////////////////////////////////////////////////////////////////// 711 | // objReadOBJ: Reads a model description from a Wavefront .OBJ file. 712 | // Returns a pointer to the created object which should be free'd with 713 | // objDelete(). 714 | // 715 | // filename - name of the file containing the Wavefront .OBJ format data. 716 | ////////////////////////////////////////////////////////////////////// 717 | bool CAccessObj::LoadOBJ(const char* filename) 718 | { 719 | FILE* file; 720 | 721 | // open the file 722 | file = fopen(filename, "r"); 723 | if (!file) 724 | { 725 | fprintf(stderr, "objReadOBJ() failed: can't open data file \"%s\".\n", 726 | filename); 727 | exit(1); 728 | } 729 | 730 | // save old model for invalid obj file 731 | COBJmodel *pOldModel = m_pModel; 732 | 733 | // allocate a new model 734 | m_pModel = new COBJmodel; 735 | 736 | sprintf(m_pModel->pathname, "%s", filename); 737 | 738 | m_pModel->nVertices = 0; 739 | m_pModel->vpVertices = NULL; 740 | m_pModel->nNormals = 0; 741 | m_pModel->vpNormals = NULL; 742 | m_pModel->nFacetnorms = 0; 743 | m_pModel->vpFacetNorms = NULL; 744 | m_pModel->nTriangles = 0; 745 | m_pModel->pTriangles = NULL; 746 | m_pModel->nGroups = 0; 747 | m_pModel->pGroups = NULL; 748 | m_pModel->position = CPoint3D (0, 0, 0); 749 | 750 | // make a first pass through the file to get a count of the number 751 | // of vertices, normals, texcoords & triangles 752 | if (FirstPass(file)) 753 | { 754 | SAFE_DELETE(pOldModel); 755 | 756 | /* allocate memory */ 757 | m_pModel->vpVertices = new CPoint3D [m_pModel->nVertices + 1]; 758 | m_pModel->pTriangles = new COBJtriangle [m_pModel->nTriangles]; 759 | if (m_pModel->nNormals) 760 | { 761 | m_pModel->vpNormals = new CPoint3D [m_pModel->nNormals + 1]; 762 | } 763 | 764 | /* rewind to beginning of file and read in the data this pass */ 765 | rewind(file); 766 | SecondPass(file); 767 | 768 | // Calc bounding box 769 | CalcBoundingBox(); 770 | } 771 | else 772 | { 773 | // restore old model 774 | if (m_pModel != NULL) Destory(); 775 | m_pModel = pOldModel; 776 | } 777 | 778 | /* close the file */ 779 | fclose(file); 780 | 781 | return (pOldModel==NULL); 782 | } 783 | 784 | void CAccessObj::Boundingbox(CPoint3D &vMax, CPoint3D &vMin) 785 | { 786 | vMax = m_vMax; 787 | vMin = m_vMin; 788 | } 789 | 790 | void CAccessObj::CalcBoundingBox() 791 | { 792 | unsigned int i; 793 | 794 | m_vMax = m_vMin = m_pModel->vpVertices[1]; 795 | for (i = 1; i <= m_pModel->nVertices; i++) 796 | { 797 | if (m_vMax.x < m_pModel->vpVertices[i].x) 798 | m_vMax.x = m_pModel->vpVertices[i].x; 799 | if (m_vMin.x > m_pModel->vpVertices[i].x) 800 | m_vMin.x = m_pModel->vpVertices[i].x; 801 | 802 | if (m_vMax.y < m_pModel->vpVertices[i].y) 803 | m_vMax.y = m_pModel->vpVertices[i].y; 804 | if (m_vMin.y > m_pModel->vpVertices[i].y) 805 | m_vMin.y = m_pModel->vpVertices[i].y; 806 | 807 | if (m_vMax.z < m_pModel->vpVertices[i].z) 808 | m_vMax.z = m_pModel->vpVertices[i].z; 809 | if (m_vMin.z > m_pModel->vpVertices[i].z) 810 | m_vMin.z = m_pModel->vpVertices[i].z; 811 | } 812 | 813 | CPoint3D vCent = (m_vMax + m_vMin)*0.5f; 814 | 815 | for (i = 1; i <= m_pModel->nVertices; i++) 816 | m_pModel->vpVertices[i] = m_pModel->vpVertices[i] - vCent; 817 | 818 | m_vMax = m_vMax - vCent; 819 | m_vMin = m_vMin -vCent; 820 | } 821 | 822 | ////////////////////////////////////////////////////////////////////////// 823 | // Unified the model to center 824 | ////////////////////////////////////////////////////////////////////////// 825 | void CAccessObj::UnifiedModel() 826 | { 827 | if (m_pModel==NULL) return; 828 | 829 | CPoint3D vDiameter = m_vMax - m_vMin; 830 | float radius = vDiameter.length() * 0.4f / 1.414f; 831 | Scale(1.0f/radius); 832 | CalcBoundingBox(); 833 | if (m_pModel->nNormals==0) 834 | { 835 | FacetNormals(); 836 | VertexNormals(90.f); 837 | } 838 | } -------------------------------------------------------------------------------- /AccessObj.h: -------------------------------------------------------------------------------- 1 | // AccessObj.h: interface for the CAccessObj class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #ifndef _MY_ACCESS_OBJ_ 6 | #define _MY_ACCESS_OBJ_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Point3D.h" 14 | 15 | #define objMax(a,b) (((a)>(b))?(a):(b)) 16 | #define objMin(a,b) (((a)<(b))?(a):(b)) 17 | #define objAbs(x) (((x)>0.f)?(x):(-x)) 18 | 19 | #define Tri(x) (m_pModel->pTriangles[(x)]) 20 | 21 | // -------------------------------------------------------------------- 22 | // COBJtriangle: defines a triangle in a model. 23 | class COBJtriangle 24 | { 25 | public: 26 | unsigned int vindices[3]; // array of triangle vertex indices 27 | unsigned int nindices[3]; // array of triangle normal indices 28 | unsigned int findex; // index of triangle facet normal 29 | COBJtriangle() 30 | { 31 | vindices[0] = vindices[1] = vindices[2] = 32 | nindices[0] = nindices[1] = nindices[2] = 0; 33 | } 34 | ~COBJtriangle() {} 35 | };// ------------------------------------------------------------------ 36 | 37 | // -------------------------------------------------------------------- 38 | // COBJgroup: defines a group in a model. 39 | class COBJgroup 40 | { 41 | public: 42 | char name[256]; // name of this group 43 | unsigned int nTriangles; // number of triangles in this group 44 | unsigned int* pTriangles; // array of triangle indices 45 | float m_fTran_X; 46 | float m_fTran_Y; 47 | float m_fTran_Z; 48 | float m_fScale_X; 49 | float m_fScale_Y; 50 | float m_fScale_Z; 51 | float m_fRotate_X; 52 | float m_fRotate_Y; 53 | float m_fRotate_Z; 54 | class COBJgroup* next; // pointer to next group in model 55 | 56 | COBJgroup() 57 | { 58 | nTriangles = 0; 59 | pTriangles = NULL; 60 | next = NULL; 61 | } 62 | 63 | ~COBJgroup() 64 | { 65 | if (nTriangles) 66 | delete [] pTriangles; 67 | pTriangles = NULL; 68 | nTriangles = 0; 69 | } 70 | };// ------------------------------------------------------------------ 71 | 72 | // -------------------------------------------------------------------- 73 | // COBJmodel: defines a model. 74 | class COBJmodel 75 | { 76 | public: 77 | char pathname[256]; // path to this model 78 | unsigned int nVertices; // number of vertices in model 79 | CPoint3D* vpVertices; // array of vertices 80 | unsigned int nNormals; // number of normals in model 81 | CPoint3D* vpNormals; // array of normals 82 | unsigned int nFacetnorms; // number of facetnorms in model 83 | CPoint3D* vpFacetNorms; // array of facetnorms 84 | unsigned int nTriangles; // number of triangles in model 85 | COBJtriangle* pTriangles; // array of triangles 86 | unsigned int nGroups; // number of groups in model 87 | COBJgroup* pGroups; // linked list of groups 88 | CPoint3D position; // position of the model 89 | 90 | // construction 91 | COBJmodel() 92 | { 93 | nVertices = 0; 94 | vpVertices = NULL; 95 | nNormals = 0; 96 | vpNormals = NULL; 97 | nFacetnorms = 0; 98 | vpFacetNorms= NULL; 99 | nTriangles = 0; 100 | pTriangles = NULL; 101 | nGroups = 0; 102 | pGroups = NULL; 103 | position = CPoint3D(0, 0, 0); 104 | } 105 | 106 | // free all memory 107 | void Destory() 108 | { 109 | COBJgroup *group; 110 | 111 | if (vpVertices) delete [] vpVertices; 112 | if (vpNormals) delete [] vpNormals; 113 | if (vpFacetNorms) delete [] vpFacetNorms; 114 | if (pTriangles) delete [] pTriangles; 115 | 116 | while(pGroups) 117 | { 118 | group = pGroups; 119 | pGroups = pGroups->next; 120 | delete group; 121 | } 122 | 123 | nVertices = 0; 124 | vpVertices = NULL; 125 | nNormals = 0; 126 | vpNormals = NULL; 127 | nFacetnorms = 0; 128 | vpFacetNorms = NULL; 129 | nTriangles = 0; 130 | pTriangles = NULL; 131 | nGroups = 0; 132 | pGroups = NULL; 133 | position = CPoint3D(0, 0, 0); 134 | } 135 | 136 | // destruction 137 | ~COBJmodel() 138 | { 139 | Destory(); 140 | } 141 | };// ------------------------------------------------------------------ 142 | 143 | // -------------------------------------------------------------------- 144 | // A temporal calss 145 | class OBJnode 146 | { 147 | public: 148 | unsigned int triIdx; 149 | unsigned int index; // index in triangle 150 | 151 | OBJnode() 152 | : triIdx(0) 153 | , index(0) 154 | { 155 | } 156 | };// ------------------------------------------------------------------ 157 | 158 | /////////////////////////////////////////////////////////////////////////////// 159 | // Definition of the OBJ R/W class 160 | /////////////////////////////////////////////////////////////////////////////// 161 | class CAccessObj 162 | { 163 | public: 164 | CAccessObj(); 165 | ~CAccessObj(); 166 | 167 | COBJmodel *m_pModel; 168 | 169 | protected: 170 | CPoint3D m_vMax, m_vMin; 171 | 172 | void CalcBoundingBox(); 173 | bool Equal(CPoint3D * u, CPoint3D * v, float epsilon); 174 | 175 | COBJgroup* FindGroup(char* name); 176 | COBJgroup* AddGroup(char* name); 177 | 178 | char* DirName(char* path); 179 | bool FirstPass(FILE* file); 180 | void SecondPass(FILE* file); 181 | void Dimensions(float* dimensions); 182 | void Scale(float scale); 183 | void ReverseWinding(); 184 | void FacetNormals(); 185 | void VertexNormals(float angle); 186 | 187 | public: 188 | void Destory(); 189 | void Boundingbox(CPoint3D &vMax, CPoint3D &vMin); 190 | bool LoadOBJ(const char* filename); 191 | void UnifiedModel(); 192 | }; 193 | 194 | #endif -------------------------------------------------------------------------------- /BasicStructure.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASIC_STRUCTURE_H_ 2 | #define _BASIC_STRUCTURE_H_ 3 | 4 | #include "MathDefs.h" 5 | #include "Mat.h" 6 | 7 | 8 | ////////////////////////////////////////////////////////////////////////// 9 | // Render System Flags 10 | ////////////////////////////////////////////////////////////////////////// 11 | 12 | // Target Type 13 | enum TargetType { SL_NONE = 0, 14 | SL_TRIANGLES, SL_TRIANGLE_STRIP, SL_TRIANGLE_FAN, 15 | SL_QUADS, SL_QUAD_STRIP, SL_POLYGON 16 | }; 17 | 18 | // Light Type 19 | enum LightType { SL_LIGHT_NONE = 0, 20 | SL_LIGHT_POINT, SL_LIGHT_SPOT, SL_LIGHT_DIRECTIONAL }; 21 | 22 | 23 | ////////////////////////////////////////////////////////////////////////// 24 | // Useful Macro 25 | ////////////////////////////////////////////////////////////////////////// 26 | #ifndef SAFE_DELETE 27 | #define SAFE_DELETE(p) if(p) { delete (p); (p)=0; } 28 | #endif 29 | 30 | #ifndef SAFE_DELETE_ARRAY 31 | #define SAFE_DELETE_ARRAY(p) if(p) { delete[] (p); (p)=0; } 32 | #endif 33 | 34 | ////////////////////////////////////////////////////////////////////////// 35 | // Definitions 36 | ////////////////////////////////////////////////////////////////////////// 37 | 38 | // Matrix 39 | typedef Mat22 Mat22d; 40 | typedef Mat33 Mat33d; 41 | typedef Matrix<4, double> Mat44d; 42 | 43 | // Light 44 | class Light 45 | { 46 | public: 47 | LightType type; 48 | Color4d ambient; 49 | Color4d diffuse; 50 | Color4d specular; 51 | Vec4d position; 52 | Vec3d direction; 53 | float spot_falloff; 54 | float spot_exponent; 55 | float attenuation0; 56 | float attenuation1; 57 | float attenuation2; 58 | Light() 59 | : type(SL_LIGHT_NONE) 60 | , ambient(0, 0 ,0, 1) 61 | , diffuse(1, 1, 1, 1) 62 | , specular(1, 1, 1, 1) 63 | , position(0, 0, 1, 1) 64 | , direction(0, 0, -1) 65 | , spot_falloff(180) 66 | , attenuation0(1) 67 | , attenuation1(0) 68 | , attenuation2(0) 69 | , spot_exponent(30) 70 | { 71 | } 72 | }; 73 | 74 | class Material 75 | { 76 | public: 77 | Color4d ambient; 78 | Color4d diffuse; 79 | Color4d ambient_diffuse; 80 | Color4d specular; 81 | double shiness; 82 | Color4d emission; 83 | 84 | Material() 85 | : ambient(0.2, 0.2, 0.2, 1.0) 86 | , diffuse(0.8, 0.8, 0.8, 1.0) 87 | , ambient_diffuse(0.5, 0.5, 0.5, 1.0) 88 | , specular(0.0, 0.0, 0.0, 1.0) 89 | , shiness(0.0) 90 | , emission(0.0, 0.0, 0.0, 1.0) 91 | { 92 | } 93 | }; 94 | 95 | #endif //_BASIC_STRUCTURE_H_ -------------------------------------------------------------------------------- /Camera.cpp: -------------------------------------------------------------------------------- 1 | #include "Camera.h" 2 | #include 3 | 4 | CCamera::CCamera(void) 5 | : mNeedUpdate(true) 6 | , mCameraPos(0, 0, 1, 1) 7 | { 8 | } 9 | 10 | CCamera::~CCamera(void) 11 | { 12 | } 13 | 14 | //------------------------------------------------------------------------------ 15 | // Camera Related 16 | //------------------------------------------------------------------------------ 17 | void CCamera::lookAt(const Vec3d& eye, const Vec3d& at, const Vec3d& up) 18 | { 19 | mCameraPos[0] = eye[0]; 20 | mCameraPos[1] = eye[1]; 21 | mCameraPos[2] = eye[2]; 22 | 23 | Vec3d t_dir = eye - at; 24 | t_dir.norm(); 25 | Vec3d t_xaxis = (up CROSS t_dir); 26 | t_xaxis.norm(); 27 | Vec3d t_up = (t_dir CROSS t_xaxis); 28 | mViewMatrix.eye(); 29 | mViewMatrix.setCol(0, t_xaxis); 30 | mViewMatrix.setCol(1, t_up); 31 | mViewMatrix.setCol(2, t_dir); 32 | mViewMatrix(3, 3) = 1; 33 | Mat44d t_mat; 34 | t_mat.translate(-eye); 35 | mViewMatrix.multiply(t_mat); 36 | 37 | mNeedUpdate = true; 38 | } 39 | 40 | void CCamera::perspective(double fovy, double aspect, double zNear, double zFar) 41 | { 42 | assert(fovy>0 && aspect>0 && zNear>0 && zFar>zNear); 43 | double top = tan(fovy/2)*zNear; 44 | double right = top * aspect; 45 | frustum(-right, right, -top, top, zNear, zFar); 46 | 47 | mNeedUpdate = true; 48 | } 49 | 50 | void CCamera::frustum(double left, double right, double bottom, double top, 51 | double near, double far) 52 | { 53 | assert(right!=left && top!=bottom && far!=near); 54 | mProjectMatrix.zero(); 55 | double skip_x = right - left; 56 | double skip_y = top - bottom; 57 | double skip_z = far - near; 58 | mProjectMatrix(0,0) = 2*near / skip_x; 59 | mProjectMatrix(1,1) = 2*near / skip_y; 60 | mProjectMatrix(2,2) = -(far+near) / skip_z; 61 | mProjectMatrix(0,2) = (left+right) /skip_x; 62 | mProjectMatrix(1,2) = (top+bottom) /skip_y; 63 | mProjectMatrix(2,3) = -2*far*near/skip_z; 64 | mProjectMatrix(3,2) = -1; 65 | 66 | mNeedUpdate = true; 67 | } 68 | 69 | void CCamera::ortho(double left, double right, double bottom, double top, 70 | double near, double far) 71 | { 72 | assert(right!=left && top!=bottom && far!=near); 73 | mProjectMatrix.zero(); 74 | double skip_x = right - left; 75 | double skip_y = top - bottom; 76 | double skip_z = far - near; 77 | mProjectMatrix(0,0) = 2 / skip_x; 78 | mProjectMatrix(1,1) = 2 / skip_y; 79 | mProjectMatrix(2,2) = -2 / skip_z; 80 | mProjectMatrix(3,3) = 1; 81 | mProjectMatrix(0,3) = -(left+right) /skip_x; 82 | mProjectMatrix(1,3) = -(top+bottom) /skip_y; 83 | mProjectMatrix(2,3) = -(far+near) / skip_z; 84 | 85 | mNeedUpdate = true; 86 | } 87 | 88 | void CCamera::transform(Vec4d& v) 89 | { 90 | if (mNeedUpdate) 91 | { 92 | mFinalMatrix = mProjectMatrix; 93 | mFinalMatrix.multiply(mViewMatrix); 94 | mNeedUpdate = false; 95 | } 96 | mFinalMatrix.transformVec(v); 97 | } 98 | -------------------------------------------------------------------------------- /Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BasicStructure.h" 4 | 5 | class CCamera 6 | { 7 | public: 8 | CCamera(void); 9 | ~CCamera(void); 10 | 11 | // camera related 12 | void lookAt(const Vec3d& eye, const Vec3d& at, const Vec3d& up); 13 | void perspective(double fovy, double aspect, double zNear, double zFar); 14 | void frustum(double left, double right, double bottom, double top, double near, double far); 15 | void ortho(double left, double right, double bottom, double top, double near, double far); 16 | void transform(Vec4d& v); 17 | const Vec4d& pos() { return mCameraPos; } 18 | 19 | private: 20 | Mat44d mModelMatrix; 21 | Mat44d mViewMatrix; 22 | Mat44d mProjectMatrix; 23 | 24 | Vec4d mCameraPos; 25 | bool mNeedUpdate; // is it needed to update @mFinalMatrix 26 | Mat44d mFinalMatrix; // ProjectMatrix * ViewMatrix 27 | }; 28 | -------------------------------------------------------------------------------- /Mat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //////////////////////////////////////////////////////////////////////////// 4 | // 5 | // used for 3d transformations 6 | // 7 | // | m00 m01 m02 m03 | <- x axis 8 | // | m10 m11 m12 m13 | <- y axis 9 | // | m20 m21 m22 m23 | <- z axis 10 | // | m30 m31 m32 m33 | <- translate 11 | 12 | #include "MathDefs.h" 13 | using trimeshVec::Vec; 14 | 15 | #define SWAP(x,y) \ 16 | tmp = m[x][y]; \ 17 | m[x][y] = m[y][x]; \ 18 | m[y][x] = tmp; 19 | 20 | template 21 | class Matrix 22 | { 23 | public: 24 | _Tp m[D][D]; 25 | Matrix() 26 | { 27 | eye(); 28 | } 29 | 30 | // No destructor or assignment operator needed 31 | 32 | // Constructor from anything that can be accessed using [] 33 | // This one's pretty aggressive, so marked explicit 34 | template explicit Matrix(const S &x) 35 | { for (int i = 0; i < D*D; i++) m[i] = _Tp(x[i]); } 36 | 37 | // Array reference and conversion to pointer - no bounds checking 38 | const _Tp* operator[] (int i) const 39 | { 40 | return m[i]; 41 | } 42 | _Tp* operator[] (int i) 43 | { 44 | return m[i]; 45 | } 46 | operator const _Tp*() const 47 | { 48 | return m; 49 | } 50 | operator _Tp*() 51 | { 52 | return m; 53 | } 54 | 55 | const _Tp& operator() (int y, int x) const 56 | { 57 | return m[y][x]; 58 | }; 59 | 60 | _Tp& operator() (int y, int x) 61 | { 62 | return m[y][x]; 63 | }; 64 | 65 | template 66 | inline Vec getCol(int y) const 67 | { 68 | VEC_STATIC_CHECK(D>=D2); 69 | Vec res; 70 | for (int i=0; i 78 | inline void setCol (unsigned int y, Vec val) 79 | { 80 | VEC_STATIC_CHECK(D>=D2); 81 | for (int i=0; i &operator += (const Matrix &x) 89 | { 90 | for (int i=0; i &operator -= (const Matrix &x) 97 | { 98 | for (int i=0; i &operator *= (const Matrix &x) 104 | { 105 | for (int i=0; i &operator *= (const _Tp &x) 111 | { 112 | for (int i=0; i &operator /= (const Matrix &x) 118 | { 119 | for (int i=0; i &operator /= (const _Tp &x) 125 | { 126 | for (int i=0; i& operator * (const Matrix &x) const 134 | { 135 | Matrix res; 136 | for (int y=0; y& multiply(const Matrix& m2) 184 | { 185 | Matrix tmp(*this); 186 | for (int y=0; y 201 | inline const Vec& transformVec (Vec &v) const 202 | { 203 | int DD = std::min(D,D2); 204 | int i,j; 205 | Vec tmp(v); 206 | for (i = 0; i < DD; i++) 207 | { 208 | v[i] = _Tp(0); 209 | for (j = 0; j < DD; j++) 210 | v[i] += m[i][j] * tmp[j]; 211 | } 212 | return (v); 213 | }; 214 | 215 | template 216 | inline const Matrix& translate(const Vec &v) 217 | { 218 | int DD = std::min(D,D2); 219 | eye(); 220 | for (int i=0; i 228 | inline const Matrix& scale(const Vec &v) 229 | { 230 | int DD = std::min(D-1,D2); 231 | eye(); 232 | for (int i=0; i 241 | class Mat22 : public Matrix<2, _Tp> 242 | { 243 | public: 244 | template 245 | Mat22<_Tp>& rotate(T2 degree); 246 | 247 | template 248 | void map(T2 x, T2 y, T2 *tx, T2 *ty); 249 | 250 | //Mat22& rotate(int degree); 251 | //Mat22& rotate(float degree); 252 | //Mat22& rotate(double degree); 253 | 254 | //void map(int x, int y, int *tx, int *ty); 255 | //void map(double x, double y, double *tx, double *ty); 256 | }; 257 | 258 | template 259 | class Mat33 : public Matrix<3, _Tp> 260 | { 261 | public: 262 | template 263 | Mat33<_Tp>& rotate(T2 degree, const Vec3d& u); 264 | }; 265 | 266 | template 267 | class Mat44 : public Matrix<4, _Tp> 268 | { 269 | }; 270 | 271 | #include "Mat.inl" -------------------------------------------------------------------------------- /Mat.inl: -------------------------------------------------------------------------------- 1 | #ifndef _MAT_INL_ 2 | #define _MAT_INL_ 3 | 4 | template 5 | template 6 | Mat22<_Tp>& Mat22<_Tp>::rotate(T2 degree) 7 | { 8 | double sina = 0, cosa = 0; 9 | 10 | if (degree == 90. || degree == -270.) 11 | sina = 1.; 12 | else if (degree == 270. || degree == -90.) 13 | sina = -1.; 14 | else if (degree == 180.) 15 | cosa = -1.; 16 | else{ 17 | double b = 3.14159 * degree / 180.0; // convert to radians 18 | sina = std::sin(double(b)); // fast and convenient 19 | cosa = std::cos(double(b)); 20 | } 21 | m[0][0] = m[1][1] = cosa; 22 | m[0][1] = -sina; 23 | m[1][0] = sina; 24 | 25 | return *this; 26 | } 27 | 28 | template 29 | template 30 | void Mat22<_Tp>::map(T2 x, T2 y, T2 *tx, T2 *ty) 31 | { 32 | *tx = T2(m[0][0]*x + m[0][1]*y); 33 | *ty = T2(m[1][0]*x + m[1][1]*y); 34 | } 35 | 36 | template 37 | template 38 | Mat33<_Tp>& Mat33<_Tp>::rotate(T2 degree, const Vec3d &u) 39 | { 40 | double sina = 0, cosa = 0; 41 | 42 | if (degree == 90. || degree == -270.) 43 | sina = 1.; 44 | else if (degree == 270. || degree == -90.) 45 | sina = -1.; 46 | else if (degree == 180.) 47 | cosa = -1.; 48 | else{ 49 | double b = 3.14159 * degree / 180.0; // convert to radians 50 | sina = std::sin(double(b)); // fast and convenient 51 | cosa = std::cos(double(b)); 52 | } 53 | double uxx = u[0]*u[0]; 54 | double uyy = u[1]*u[1]; 55 | double uzz = u[2]*u[2]; 56 | double uxy = u[0]*u[1]; 57 | double uxz = u[0]*u[2]; 58 | double uyz = u[1]*u[2]; 59 | m[0][0] = uxx+(1-uxx)*cosa; 60 | m[1][1] = uyy+(1-uyy)*cosa; 61 | m[2][2] = uzz+(1-uzz)*cosa; 62 | m[0][1] = uxy*(1-cosa)-u[2]*sina; 63 | m[0][1] = uxz*(1-cosa)+u[1]*sina; 64 | m[1][0] = uxy*(1-cosa)+u[2]*sina; 65 | m[1][2] = uyz*(1-cosa)-u[0]*sina; 66 | m[2][0] = uxz*(1-cosa)-u[1]*sina; 67 | m[2][1] = uyz*(1-cosa)+u[0]*sina; 68 | 69 | return *this; 70 | } 71 | #endif//_MAT_INL_ -------------------------------------------------------------------------------- /MathDefs.h: -------------------------------------------------------------------------------- 1 | #ifndef _MATHDEFS_H_ 2 | #define _MATHDEFS_H_ 3 | 4 | #include "Vec.h" 5 | 6 | ////////////////////////////////////////////////////////////////////////// 7 | // Useful Structures 8 | // 9 | typedef unsigned char byte; 10 | typedef trimeshVec::Vec<2, double> Vec2d; 11 | typedef trimeshVec::Vec<3, int> Vec3i; 12 | typedef trimeshVec::Vec<3, double> Vec3d; 13 | typedef trimeshVec::Vec<4, double> Vec4d; 14 | 15 | typedef trimeshVec::Vec<3, byte> Color3u; 16 | typedef trimeshVec::Vec<4, byte> Color4u; 17 | typedef Vec3d Color3d; 18 | typedef Vec4d Color4d; 19 | typedef Vec3d Normald; 20 | 21 | #endif// _MATHDEFS_H_ -------------------------------------------------------------------------------- /Point3D.cpp: -------------------------------------------------------------------------------- 1 | #include "Point3D.h" 2 | #include 3 | #include 4 | 5 | #define Pi 3.14159 6 | 7 | using namespace std; 8 | //------------------------------------------------------------------------------ 9 | // constructor 10 | //------------------------------------------------------------------------------ 11 | CPoint3D::CPoint3D( ) // normal constructor 12 | { 13 | x = 0; y = 0; z = 0; 14 | } 15 | 16 | CPoint3D::CPoint3D( const CPoint3D &v ) 17 | { 18 | x = v.x; 19 | y = v.y; 20 | z = v.z; 21 | } 22 | 23 | CPoint3D::CPoint3D( int xx, int yy, int zz ) // normal constructor 24 | { 25 | x = (float)xx; y = (float)yy; z = (float)zz; 26 | } 27 | 28 | CPoint3D::CPoint3D( float xx, float yy, float zz ) // normal constructor 29 | { 30 | x = xx; y = yy; z = zz; 31 | } 32 | 33 | CPoint3D::CPoint3D( double xx, double yy, double zz ) // normal constructor 34 | { 35 | x = (float)xx; y = (float)yy; z = (float)zz; 36 | } 37 | 38 | //------------------------------------------------------------------------------ 39 | // destructor 40 | //------------------------------------------------------------------------------ 41 | CPoint3D::~CPoint3D(void) 42 | { 43 | } 44 | 45 | //------------------------------------------------------------------------------ 46 | // Plus 47 | //------------------------------------------------------------------------------ 48 | const CPoint3D& CPoint3D::operator +=(const CPoint3D &v) 49 | { 50 | x += v.x; 51 | y += v.y; 52 | z += v.z; 53 | return *this; 54 | } 55 | 56 | //------------------------------------------------------------------------------ 57 | // Subtraction 58 | //------------------------------------------------------------------------------ 59 | const CPoint3D& CPoint3D::operator -=(const CPoint3D &v) 60 | { 61 | x -= v.x; 62 | y -= v.y; 63 | z -= v.z; 64 | return *this; 65 | } 66 | 67 | //------------------------------------------------------------------------------ 68 | // CVectors plus 69 | //------------------------------------------------------------------------------ 70 | CPoint3D CPoint3D::operator + ( const CPoint3D& v ) 71 | { 72 | CPoint3D r(*this); 73 | r += v; 74 | return ( r ); 75 | } 76 | 77 | //------------------------------------------------------------------------------ 78 | // CVectors subtraction 79 | //------------------------------------------------------------------------------ 80 | CPoint3D CPoint3D::operator - ( const CPoint3D& v ) 81 | { 82 | CPoint3D r(*this); 83 | r -= v; 84 | return ( r ); 85 | } 86 | 87 | //------------------------------------------------------------------------------ 88 | // CVectors cross product 89 | //------------------------------------------------------------------------------ 90 | CPoint3D CPoint3D::operator * ( const CPoint3D& v ) 91 | { 92 | CPoint3D r; 93 | 94 | r.x = y*v.z - v.y*z; 95 | r.y = v.x*z - x*v.z; 96 | r.z = x*v.y - v.x*y; 97 | 98 | return( r ); 99 | } 100 | 101 | //------------------------------------------------------------------------------ 102 | // CPoint3D scale 103 | //------------------------------------------------------------------------------ 104 | CPoint3D CPoint3D::operator * ( int k ) // scaled by int 105 | { 106 | CPoint3D r; 107 | 108 | r.x = x * (float)k; 109 | r.y = y * (float)k; 110 | r.z = z * (float)k; 111 | 112 | return( r ); 113 | } 114 | CPoint3D CPoint3D::operator * ( float k ) // scaled by float 115 | { 116 | CPoint3D r; 117 | 118 | r.x = x * k; 119 | r.y = y * k; 120 | r.z = z * k; 121 | 122 | return( r ); 123 | } 124 | CPoint3D CPoint3D::operator * ( double k ) // scaled by double 125 | { 126 | CPoint3D r; 127 | 128 | r.x = x * (float)k; 129 | r.y = y * (float)k; 130 | r.z = z * (float)k; 131 | 132 | return( r ); 133 | } 134 | 135 | //------------------------------------------------------------------------------ 136 | // CVectors dot product 137 | //------------------------------------------------------------------------------ 138 | float CPoint3D::operator & ( const CPoint3D& v ) 139 | { 140 | return ( x * v.x + y * v.y + z * v.z ); 141 | } 142 | 143 | //------------------------------------------------------------------------------ 144 | // CPoint3D length 145 | //------------------------------------------------------------------------------ 146 | float CPoint3D::length() 147 | { 148 | return( (float)sqrt( x*x + y*y + z*z ) ); 149 | } 150 | 151 | //------------------------------------------------------------------------------ 152 | // CPoint3D unify 153 | //------------------------------------------------------------------------------ 154 | void CPoint3D::unify() 155 | { 156 | float len = length(); 157 | 158 | if( len < 1.0e-20 ) 159 | { 160 | x = float(rand()%1000+20); 161 | y = float(rand()%1000+20); 162 | z = float(rand()%1000+20); 163 | len=length(); 164 | x/=len; 165 | y/=len; 166 | z/=len; 167 | } 168 | 169 | 170 | else 171 | { 172 | len = 1.0f/len; 173 | x *= len; 174 | y *= len; 175 | z *= len; 176 | } 177 | } 178 | 179 | void CPoint3D::RangeUnify(float min,float max) 180 | { 181 | if (x>max) x=max; 182 | if (y>max) y=max; 183 | if (z>max) z=max; 184 | 185 | if (x 0; } 23 | inline bool isBlending() const { return (mState&SL_BLENDING) > 0; } 24 | 25 | private: 26 | int mState; 27 | }; 28 | -------------------------------------------------------------------------------- /ScanLine.cpp: -------------------------------------------------------------------------------- 1 | #include "ScanLine.h" 2 | #include 3 | #include 4 | #include 5 | #include "Point3D.h" 6 | 7 | using std::fabs; 8 | using std::max; 9 | using std::min; 10 | using std::tan; 11 | using trimeshVec::normalize; 12 | 13 | #define SATURATE(x) ( ((x)>255) ? 255 : (((x)<0) ? 0 : x) ) 14 | #define ROUND(x) int((x)+0.5) 15 | #define DEFAULT_COLOR Color4u(255, 255, 255, 255) 16 | 17 | #define DISABLE_STATE(state,pro) {(state) &= ~(pro);} 18 | #define EABLE_STATE(state,pro) {(state) |= (pro);} 19 | 20 | ////////////////////////////////////////////////////////////////////////// 21 | CScanLine::CScanLine() 22 | : mType(SL_NONE), mMaxY(-1) 23 | , mbInitialised(false) 24 | , mbHasNormals(true) 25 | { 26 | _init(); 27 | } 28 | 29 | CScanLine::CScanLine(int _w, int _h, QImage* _img) 30 | : mType(SL_NONE), mMaxY(-1), mCurY(_h-1) 31 | , mHeight(_h), mWidth(_w), mImg(_img) 32 | , mZBuffer(_h*_w, 1.0) 33 | , mbInitialised(true) 34 | , mbHasNormals(true) 35 | { 36 | _init(); 37 | } 38 | 39 | void CScanLine::_init() 40 | { 41 | mCurColor[0] = 1.0; 42 | mCurColor[1] = 1.0; 43 | mCurColor[2] = 1.0; 44 | mCurColor[3] = 1.0; 45 | 46 | mCurNormal[0] = 0; 47 | mCurNormal[1] = 0; 48 | mCurNormal[2] = 0; 49 | 50 | mGlobalAmbient = Color4d(0.1, 0.1, 0.1, 1.0); 51 | 52 | } 53 | 54 | void CScanLine::setRenderTarget(int _w, int _h, QImage *_img) 55 | { 56 | mCurY = _h-1; 57 | mWidth = _w; 58 | mHeight = _h; 59 | mImg = _img; 60 | mZBuffer.assign(_w*_h, 1.0); 61 | 62 | mbInitialised = true; 63 | } 64 | 65 | CScanLine::~CScanLine(void) 66 | { 67 | _clear(); 68 | } 69 | 70 | void CScanLine::_clear() 71 | { 72 | ETableIterator it = mSortedET.begin(); 73 | ETableIterator it_end = mSortedET.end(); 74 | for (; it!=it_end; ++it) 75 | { 76 | EListIterator itl = it->second.begin(); 77 | EListIterator itl_end = it->second.end(); 78 | for (; itl!=itl_end; ++itl ) 79 | { 80 | SAFE_DELETE(*itl); 81 | } 82 | } 83 | 84 | TArrayItor itt = mTriArray.begin(); 85 | TArrayItor itt_end = mTriArray.end(); 86 | for (; itt!=itt_end; ++itt) 87 | { 88 | SAFE_DELETE(*itt); 89 | } 90 | 91 | VBufferItor itv = mVertexBuffer.begin(); 92 | VBufferItor itv_end = mVertexBuffer.end(); 93 | for (; itv!=itv_end; ++itv) 94 | { 95 | SAFE_DELETE(*itv); 96 | } 97 | 98 | mSortedET.clear(); 99 | mTriArray.clear(); 100 | mAEL.clear(); 101 | 102 | mVertexBuffer.clear(); 103 | } 104 | 105 | void CScanLine::clear(int _target, const Color4u& _c /* = Color4u */, double _depth /* = 1.0 */) 106 | { 107 | if (_target & SL_COLOR_BUFFER) 108 | { 109 | mImg->fill(qRgba(_c[0], _c[1], _c[2], _c[3])); 110 | } 111 | if (_target & SL_DEPTH_BUFFER) 112 | { 113 | // z buffer reassignment 114 | mZBuffer.assign(mWidth*mHeight, _depth); 115 | } 116 | } 117 | 118 | void CScanLine::begin(TargetType _type) 119 | { 120 | if (!mbInitialised) return; 121 | 122 | mType = _type; 123 | 124 | _clear(); 125 | mMaxY = -1; 126 | mCurY = mHeight-1; 127 | } 128 | 129 | //------------------------------------------------------------------------------ 130 | // Vertices 131 | //------------------------------------------------------------------------------ 132 | void CScanLine::vertex3d(double _x, double _y, double _z) 133 | { 134 | Vertex *t_pv = new Vertex(_x, _y, _z, 1); 135 | t_pv->color = mCurColor; 136 | t_pv->normalWorld = mCurNormal; 137 | mVertexBuffer.push_back(t_pv); 138 | } 139 | 140 | void CScanLine::vertex3dv(const Vec3d& v) 141 | { 142 | vertex3d(v[0], v[1], v[2]); 143 | } 144 | 145 | void CScanLine::vertex3fv(const CPoint3D& v) 146 | { 147 | vertex3d(v.x, v.y, v.z); 148 | } 149 | 150 | //------------------------------------------------------------------------------ 151 | // Colors 152 | //------------------------------------------------------------------------------ 153 | void CScanLine::color3i(unsigned char _r, unsigned char _g, unsigned char _b) 154 | { 155 | mCurColor[0] = _r/255.0; 156 | mCurColor[1] = _g/255.0; 157 | mCurColor[2] = _b/255.0; 158 | mCurColor[3] = 1.0; 159 | } 160 | 161 | void CScanLine::color4i(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a) 162 | { 163 | mCurColor[0] = _r/255.0; 164 | mCurColor[1] = _g/255.0; 165 | mCurColor[2] = _b/255.0; 166 | mCurColor[3] = _a/255.0; 167 | } 168 | 169 | void CScanLine::color3f(float _r, float _g, float _b) 170 | { 171 | mCurColor[0] = _r; 172 | mCurColor[1] = _g; 173 | mCurColor[2] = _b; 174 | mCurColor[3] = 1.0; 175 | } 176 | 177 | void CScanLine::color4f(float _r, float _g, float _b, float _a) 178 | { 179 | mCurColor[0] = _r; 180 | mCurColor[1] = _g; 181 | mCurColor[2] = _b; 182 | mCurColor[3] = _a; 183 | } 184 | 185 | //------------------------------------------------------------------------------ 186 | // Normals 187 | //------------------------------------------------------------------------------ 188 | void CScanLine::normal3d(double _nx, double _ny, double _nz) 189 | { 190 | mCurNormal[0] = _nx; 191 | mCurNormal[1] = _ny; 192 | mCurNormal[2] = _nz; 193 | } 194 | 195 | void CScanLine::normal3fv(const CPoint3D& _n) 196 | { 197 | mCurNormal[0] = _n.x; 198 | mCurNormal[1] = _n.y; 199 | mCurNormal[2] = _n.z; 200 | } 201 | 202 | //void CScanLine::setLight(const Light& light) 203 | //{ 204 | // if (mLights.empty()) 205 | // mLights.push_back(light); 206 | // else 207 | // mLights[0] = light; 208 | // 209 | // mLights.back().direction.norm(); 210 | //} 211 | 212 | void CScanLine::end() 213 | { 214 | _modelViewProjectionTransform(); 215 | //_normalizeDeviceCoordinates(); 216 | _screenCoordinates(); 217 | switch (mType) 218 | { 219 | case SL_TRIANGLES: 220 | _addTriangles(); 221 | break; 222 | 223 | case SL_TRIANGLE_STRIP: 224 | _addTriangleStrip(); 225 | break; 226 | 227 | case SL_TRIANGLE_FAN: 228 | _addTriangleFan(); 229 | break; 230 | 231 | case SL_QUADS: 232 | _addQuads(); 233 | break; 234 | 235 | case SL_QUAD_STRIP: 236 | _addQuadStrip(); 237 | break; 238 | 239 | case SL_POLYGON: 240 | _addPolygon(); 241 | return; 242 | break; 243 | 244 | case SL_NONE: 245 | return; 246 | break; 247 | 248 | default : 249 | return; 250 | break; 251 | } 252 | 253 | _scanLine(); 254 | 255 | mType = SL_NONE; 256 | } 257 | 258 | void CScanLine::_addTriangles() 259 | { 260 | int v_num = mVertexBuffer.size()/3; 261 | for (int i=0; iposScreen[1] == _v2->posScreen[1] && _v1->posScreen[1] == _v3->posScreen[1]) 275 | return; 276 | 277 | Normald t_nor = (_v2->posScreen - _v1->posScreen) CROSS (_v3->posScreen - _v1->posScreen); 278 | if (t_nor[2]<0) // back cull, faster 279 | return; 280 | 281 | Triangle *tri = new Triangle; 282 | tri->normal = t_nor; 283 | tri->d = -(tri->normal DOT _v1->posScreen); 284 | int t_minY = min(_v3->posScreen[1], min(_v1->posScreen[1], _v2->posScreen[1])); 285 | int t_maxY = max(_v3->posScreen[1], max(_v1->posScreen[1], _v2->posScreen[1])); 286 | tri->dy = t_maxY - t_minY; 287 | 288 | int t_id = mTriArray.size(); 289 | _addEdge(_v1, _v2, t_id); 290 | _addEdge(_v2, _v3, t_id); 291 | _addEdge(_v3, _v1, t_id); 292 | 293 | mTriArray.push_back(tri); 294 | } 295 | 296 | bool CScanLine::_addEdge(const Vertex* _v1, const Vertex* _v2, int _id) 297 | { 298 | assert(_id==mTriArray.size()); 299 | 300 | if (_v1->posScreen[1] == _v2->posScreen[1]) 301 | return false; 302 | 303 | // clipping 304 | 305 | // swap, so that y coordinates are sorted decreasingly 306 | if (_v1->posScreen[1] < _v2->posScreen[1]) 307 | { 308 | const Vertex *t_v = _v1; 309 | _v1 = _v2; 310 | _v2 = t_v; 311 | } 312 | 313 | // create edge 314 | Edge *edge = new Edge; 315 | edge->id = _id; 316 | 317 | edge->dy = _v1->posScreen[1] - _v2->posScreen[1]; 318 | edge->x = _v2->posScreen[0]; 319 | edge->dx = (_v1->posScreen[0] - _v2->posScreen[0]) * 1.0 / edge->dy; 320 | 321 | //color 322 | const Color4d &c1 = _v1->color; 323 | const Color4d &c2 = _v2->color; 324 | edge->color = c2; 325 | edge->dclr = (c1 - c2); 326 | edge->dclr /= 1.0 * edge->dy; 327 | 328 | // position in world space 329 | const Vec4d &p1 = _v1->posWorld; 330 | const Vec4d &p2 = _v2->posWorld; 331 | edge->posW = p2; 332 | edge->dPosW = (p1 - p2); 333 | edge->dPosW /= 1.0 * edge->dy; 334 | 335 | // normal in world space 336 | if (mRenderState.isLighting()) 337 | { 338 | const Normald &n1 = _v1->normalWorld; 339 | const Normald &n2 = _v2->normalWorld; 340 | edge->normalW = n2; 341 | edge->dNorW = (n1 - n2); 342 | edge->dNorW /= 1.0 * edge->dy; 343 | } 344 | 345 | // add new edge 346 | mSortedET[_v2->posScreen[1]].push_back(edge); 347 | 348 | if (_v2->posScreen[1] < mCurY) 349 | mCurY = _v2->posScreen[1]; 350 | 351 | if (_v1->posScreen[1] > mMaxY) // && _v1->posScreen[1] < mHeight) 352 | mMaxY = _v1->posScreen[1]; 353 | 354 | return true; 355 | } 356 | 357 | void CScanLine::_addTriangleStrip() 358 | { 359 | int v_num = mVertexBuffer.size(); 360 | 361 | for (int i=0; ix == e2->x) ? (e1->dx < e2->dx) : (e1->x < e2->x); 403 | } 404 | 405 | void CScanLine::_scanLine() 406 | { 407 | if (mMaxY>=mHeight) mMaxY=mHeight-1; 408 | 409 | int nNextY = mCurY; // the line which will be added next time 410 | ETableIterator itset_next = mSortedET.begin(); // related iterator 411 | while (mCurY<=mMaxY) 412 | { 413 | ActiveEdge *t_ae; 414 | AEListItor itae, itae_end; 415 | 416 | // Step 1: add edges at mCurY line to Active Edge List 417 | //ETableIterator it_set = mSortedET.find(mCurY); 418 | if (mCurY==nNextY && itset_next != mSortedET.end() 419 | && !(itset_next->second.empty())) 420 | { 421 | EListIterator itl = itset_next->second.begin(); 422 | EListIterator itl_end = itset_next->second.end(); 423 | for (; itl!=itl_end; ++itl) 424 | { 425 | int id = (*itl)->id; 426 | itae = mAEL.find(id); 427 | if (itae!=mAEL.end()) 428 | { 429 | t_ae = &(itae->second); 430 | if (t_ae->el->dy == 0) 431 | t_ae->el = *itl; 432 | if (t_ae->er->dy == 0) 433 | t_ae->er = *itl; 434 | } 435 | else 436 | { // if it's a new triangle 437 | //Edge *el = *itl; 438 | //++itl; 439 | //Edge *er = *itl; 440 | //if (el->id!=er->id) 441 | //{ 442 | // int i = 0; 443 | //} 444 | ActiveEdge *t_ae = &mAEL[id]; 445 | //t_ae->el = el; 446 | //t_ae->er = er; 447 | t_ae->el = *itl; 448 | ++itl; 449 | assert(t_ae->el->id == (*itl)->id); 450 | t_ae->er = *itl; 451 | if (!_compare_edges(t_ae->el, t_ae->er)) 452 | { 453 | Edge* t_e = t_ae->er; 454 | t_ae->er = t_ae->el; 455 | t_ae->el = t_e; 456 | } 457 | // calculate z depth at left 458 | Triangle &tri = *(mTriArray[id]); 459 | Edge *t_el = t_ae->el; 460 | t_ae->zl = -(tri.normal[0]*t_el->x + tri.normal[1]*mCurY + tri.d) / (tri.normal[2]); 461 | t_ae->dzx = -tri.normal[0] / tri.normal[2]; 462 | t_ae->dzy = -tri.normal[1] / tri.normal[2]; 463 | } 464 | } 465 | ++itset_next; 466 | if (itset_next != mSortedET.end()) 467 | nNextY = itset_next->first; 468 | }// end if (mCurY==nNextY && it_set != mSortedET.end() && !(it_set->second.empty())) 469 | 470 | if (mCurY>=0) 471 | { 472 | // Step 2: fill the region in pairs, horizontal operations 473 | itae = mAEL.begin(); 474 | itae_end = mAEL.end(); 475 | for (; itae!=itae_end; ++itae ) 476 | { 477 | t_ae = &(itae->second); 478 | Edge *e1 = t_ae->el; 479 | Edge *e2 = t_ae->er; 480 | 481 | double t_xl = e1->x; // valid x on the left side 482 | double t_xr = e2->x; // valid x on the right side 483 | // skip the scan line which is out of region 484 | if (t_xl>=mWidth || t_xr<0) 485 | {// out of area 486 | continue; 487 | } 488 | 489 | // calculate the interpolated color 490 | double skip_x = e2->x - e1->x; 491 | 492 | Color4d t_dclr(0, 0, 0, 0); 493 | Vec4d t_dposW(0,0,0,0); 494 | Normald t_dnorW(0, 0, 0); 495 | if (skip_x>0) 496 | { 497 | t_dclr = (e2->color - e1->color) / skip_x; 498 | if ( mRenderState.isSmoothShading() ) 499 | { 500 | t_dposW = (e2->posW - e1->posW) / skip_x; 501 | t_dnorW = (e2->normalW - e1->normalW) / skip_x; 502 | } 503 | } 504 | Color4d t_color = e1->color; 505 | Vec4d t_posW = e1->posW; 506 | Normald t_norW = e1->normalW; 507 | double t_zl = t_ae->zl; // z depth on the left side 508 | 509 | // skip the region over the left 510 | if (t_xl<0) 511 | { 512 | t_color += t_dclr*(-t_xl); 513 | if (mRenderState.isSmoothShading()) 514 | { 515 | t_posW += t_dposW*(-t_xl); 516 | t_norW += t_dnorW*(-t_xl); 517 | } 518 | t_xl = 0; 519 | } 520 | 521 | Color4d t_final_clr; 522 | //for (int pi = std::max(e1->x,0.0); pix+1, (double)mImg->width()); ++pi) 523 | for (int pi = int(t_xl); pidzx; 536 | if ( mRenderState.isSmoothShading() ) 537 | { 538 | t_posW += t_dposW; 539 | t_norW += t_dnorW; 540 | } 541 | } 542 | } 543 | } 544 | 545 | // Step 3: update the edges, vertical operations 546 | itae = mAEL.begin(); 547 | itae_end = mAEL.end(); 548 | if (mCurY<0) 549 | { 550 | double nMinY = -mCurY; // NOTE 551 | if (itset_next != mSortedET.end() && !(itset_next->second.empty()) 552 | && (nNextY-mCurY < nMinY) ) 553 | { 554 | nMinY = nNextY-mCurY; 555 | } 556 | if (nMinY) 557 | for (; itae!=itae_end; ++itae) 558 | { 559 | t_ae = &(itae->second); 560 | if (t_ae->el->dy < nMinY) 561 | { 562 | nMinY = t_ae->el->dy; 563 | } 564 | if (t_ae->er->dy < nMinY) 565 | { 566 | nMinY = t_ae->er->dy; 567 | } 568 | } 569 | itae = mAEL.begin(); 570 | for (; itae!=itae_end;) 571 | { 572 | t_ae = &(itae->second); 573 | 574 | // dy 575 | t_ae->el->dy -= nMinY; 576 | t_ae->er->dy -= nMinY; 577 | 578 | if (t_ae->el->dy == 0 && t_ae->er->dy == 0) 579 | { 580 | itae = mAEL.erase(itae); 581 | continue; 582 | } 583 | 584 | // x, zl 585 | t_ae->el->x += t_ae->el->dx * nMinY; 586 | t_ae->er->x += t_ae->er->dx * nMinY; 587 | t_ae->zl += (t_ae->dzx * t_ae->el->dx + t_ae->dzy) * nMinY; 588 | 589 | // color 590 | t_ae->el->color += t_ae->el->dclr * nMinY; 591 | t_ae->er->color += t_ae->er->dclr * nMinY; 592 | 593 | if ( mRenderState.isSmoothShading() ) 594 | { 595 | // normal in WS 596 | t_ae->el->normalW += t_ae->el->dNorW * nMinY; 597 | t_ae->er->normalW += t_ae->er->dNorW * nMinY; 598 | 599 | // position in WS 600 | t_ae->el->posW += t_ae->el->dPosW * nMinY; 601 | t_ae->er->posW += t_ae->er->dPosW * nMinY; 602 | } 603 | 604 | ++itae; 605 | } 606 | mCurY += int(nMinY); 607 | } 608 | else 609 | {// mCurY>=0 610 | for (; itae!=itae_end;) 611 | { 612 | // remove the edges whose nearby edge is at the other side of the scan line. 613 | t_ae = &(itae->second); 614 | if (t_ae->el->dy == 0 && t_ae->er->dy == 0) 615 | { 616 | itae = mAEL.erase(itae); 617 | } 618 | else 619 | { 620 | // dy 621 | --t_ae->el->dy; 622 | --t_ae->er->dy; 623 | 624 | // x, zl 625 | t_ae->el->x += t_ae->el->dx; 626 | t_ae->er->x += t_ae->er->dx; 627 | t_ae->zl += t_ae->dzx * t_ae->el->dx + t_ae->dzy; 628 | 629 | // color 630 | t_ae->el->color += t_ae->el->dclr; 631 | t_ae->er->color += t_ae->er->dclr; 632 | 633 | if ( mRenderState.isSmoothShading() ) 634 | { 635 | // normal in WS 636 | t_ae->el->normalW += t_ae->el->dNorW; 637 | t_ae->er->normalW += t_ae->er->dNorW; 638 | 639 | // position in WS 640 | t_ae->el->posW += t_ae->el->dPosW; 641 | t_ae->er->posW += t_ae->er->dPosW; 642 | } 643 | 644 | ++itae; 645 | } 646 | }//end for update edges 647 | ++mCurY; 648 | } 649 | } 650 | } 651 | 652 | void CScanLine::_setFrameBuffer(int _y, int _x, Color4d& _clr) 653 | { 654 | if (mRenderState.isBlending()) 655 | { 656 | QRgb oldclr = mImg->pixel(_x, mHeight-_y-1); 657 | double t_a = _clr[3]; 658 | _clr[0] = _clr[0] * t_a + qRed(oldclr) * (1-t_a); 659 | _clr[1] = _clr[1] * t_a + qGreen(oldclr) * (1-t_a); 660 | _clr[2] = _clr[2] * t_a + qBlue(oldclr) * (1-t_a); 661 | _clr[3] = 1.0; 662 | } 663 | _clr *= 255.0; 664 | mImg->setPixel(_x, mHeight-_y-1, 665 | qRgb(SATURATE(_clr[0]), SATURATE(_clr[1]), SATURATE(_clr[2])) ); 666 | } 667 | 668 | void CScanLine::_calculateLight(const Vec4d& _pos, const Normald& _nor, Color4d& _clr) 669 | { 670 | if ( !mRenderState.isLighting()) 671 | return; 672 | 673 | Normald normal = _nor.normed(); 674 | Color4d diffuse, ambient, specular, globalAmbient, finalColor; 675 | double NdotL, NdotHV, dist, att; 676 | 677 | Vec3d lightDir, halfVector; 678 | Vec3d eyeDir = mCamera.pos() - _pos; 679 | dist = eyeDir.length(); 680 | eyeDir.norm(); 681 | 682 | 683 | switch(mLight.type) 684 | { 685 | case SL_LIGHT_DIRECTIONAL: 686 | lightDir = -mLight.direction; 687 | lightDir.norm(); 688 | NdotL = std::max((normal DOT lightDir), 0.0); 689 | //diffuse = mMaterial.diffuse * mLight.diffuse; 690 | //ambient = mMaterial.ambient * mLight.ambient; 691 | globalAmbient = mMaterial.ambient * mGlobalAmbient; 692 | finalColor =globalAmbient; 693 | // specular 694 | if (NdotL>0) 695 | { 696 | diffuse = _clr * mLight.diffuse; 697 | ambient = _clr * mLight.ambient; 698 | halfVector = lightDir + eyeDir; 699 | halfVector.norm(); 700 | NdotHV = std::max((normal DOT halfVector), 0.0); 701 | specular = mMaterial.specular * mLight.specular * std::pow(NdotHV, mMaterial.shiness); 702 | finalColor += NdotL * diffuse + specular + ambient; 703 | } 704 | _clr = finalColor; 705 | _clr[3] = 1.0; 706 | break; 707 | case SL_LIGHT_POINT: 708 | lightDir = mLight.position - _pos; 709 | lightDir.norm(); 710 | NdotL = std::max((normal DOT lightDir), 0.0); 711 | //diffuse = mMaterial.diffuse * mLight.diffuse; 712 | //ambient = mMaterial.ambient * mLight.ambient; 713 | globalAmbient = mMaterial.ambient * mGlobalAmbient; 714 | finalColor = globalAmbient; 715 | // specular 716 | if (NdotL>0) 717 | { 718 | diffuse = _clr * mLight.diffuse; 719 | ambient = _clr * mLight.ambient; 720 | att = 1.0 / (mLight.attenuation0 + mLight.attenuation1 * dist + 721 | mLight.attenuation2 * dist *dist); 722 | halfVector = (lightDir + eyeDir).normed(); 723 | NdotHV = std::max((normal DOT halfVector), 0.0); 724 | specular = mMaterial.specular * mLight.specular * std::pow(NdotHV, mMaterial.shiness); 725 | // final color 726 | finalColor += att * (NdotL * diffuse + ambient + specular); 727 | } 728 | _clr = finalColor; 729 | _clr[3] = 1.0; 730 | break; 731 | case SL_LIGHT_SPOT: 732 | break; 733 | case SL_LIGHT_NONE: 734 | break; 735 | default: 736 | break; 737 | } 738 | } 739 | 740 | //------------------------------------------------------------------------------ 741 | // Camera Related 742 | //------------------------------------------------------------------------------ 743 | void CScanLine::lookAt(const Vec3d& eye, const Vec3d& at, const Vec3d& up) 744 | { 745 | mCamera.lookAt(eye, at, up); 746 | } 747 | 748 | void CScanLine::perspective(double fovy, double aspect, double zNear, double zFar) 749 | { 750 | mCamera.perspective(fovy, aspect, zNear, zFar); 751 | } 752 | 753 | void CScanLine::frustum(double left, double right, double bottom, double top, 754 | double near, double far) 755 | { 756 | mCamera.frustum(left, right, bottom, top, near, far); 757 | } 758 | 759 | void CScanLine::ortho(double left, double right, double bottom, double top, 760 | double near, double far) 761 | { 762 | mCamera.ortho(left, right, bottom, top, near, far); 763 | } 764 | 765 | //------------------------------------------------------------------------------ 766 | // Transformations 767 | //------------------------------------------------------------------------------ 768 | void CScanLine::_normalizeDeviceCoordinates() 769 | { 770 | VBufferItor it = mVertexBuffer.begin(); 771 | VBufferItor it_end = mVertexBuffer.end(); 772 | for (; it!=it_end; ++it) 773 | { 774 | Vertex *t_pv = *it; 775 | t_pv->posWorld[0] /= t_pv->posWorld[3]; 776 | t_pv->posWorld[1] /= t_pv->posWorld[3]; 777 | t_pv->posWorld[2] /= t_pv->posWorld[3]; 778 | t_pv->posWorld[3] = 1; 779 | } 780 | } 781 | 782 | void CScanLine::_screenCoordinates() 783 | { 784 | VBufferItor it = mVertexBuffer.begin(); 785 | VBufferItor it_end = mVertexBuffer.end(); 786 | for (; it!=it_end; ++it) 787 | { 788 | Vertex *t_pv = *it; 789 | // round the coordinates 790 | t_pv->posScreen[0] = ROUND((t_pv->posScreen[0]+1)*mWidth*0.5); 791 | t_pv->posScreen[1] = ROUND((t_pv->posScreen[1]+1)*mHeight*0.5); 792 | t_pv->posScreen[2] = 0.5 * t_pv->posScreen[2] + 0.5; 793 | } 794 | } 795 | 796 | void CScanLine::_modelViewProjectionTransform() 797 | { 798 | Vertex *t_pv; 799 | Vec4d t_pos; 800 | 801 | VBufferItor it = mVertexBuffer.begin(); 802 | VBufferItor it_end = mVertexBuffer.end(); 803 | for (; it!=it_end; ++it) 804 | { 805 | t_pv = *it; 806 | t_pos = t_pv->posWorld; 807 | mCamera.transform(t_pos); 808 | t_pv->posScreen[0] = t_pos[0] / t_pos[3]; 809 | t_pv->posScreen[1] = t_pos[1] / t_pos[3]; 810 | t_pv->posScreen[2] = t_pos[2] / t_pos[3]; 811 | 812 | // gouraud shading 813 | if ( mRenderState.isFlatShading() ) 814 | _calculateLight(t_pv->posWorld, t_pv->normalWorld, t_pv->color); 815 | } 816 | } 817 | 818 | void CScanLine::_vertexTransform() 819 | { 820 | _modelViewProjectionTransform(); 821 | } 822 | 823 | //------------------------------------------------------------------------------ 824 | // Render States 825 | //------------------------------------------------------------------------------ 826 | void CScanLine::setRenderState(int _state, int _val) 827 | { 828 | mRenderState.setState(_state, _val); 829 | } -------------------------------------------------------------------------------- /ScanLine.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxint/zbuffer-cpu/e014c783a25bbd0ff19c7bfc6846d6997bee227e/ScanLine.h -------------------------------------------------------------------------------- /Vec.h: -------------------------------------------------------------------------------- 1 | #ifndef VEC_H 2 | #define VEC_H 3 | /* 4 | Szymon Rusinkiewicz 5 | Princeton University 6 | 7 | Vec.h 8 | Class for a constant-length vector 9 | 10 | Supports the following operations: 11 | vec v1; // Initialized to (0,0,0) 12 | vec v2(1,2,3); // Initializes the 3 components 13 | vec v3(v2); // Copy constructor 14 | float farray[3]; 15 | vec v4 = vec(farray); // Explicit: "v4 = farray" won't work 16 | Vec<3,double> vd; // The "vec" used above is Vec<3,float> 17 | point p1, p2, p3; // Same as vec 18 | 19 | v3 = v1 + v2; // Also -, *, / (all componentwise) 20 | v3 = 3.5f * v1; // Also vec * scalar, vec / scalar 21 | // NOTE: scalar has to be the same type: 22 | // it won't work to do double * vec 23 | 24 | v3 = v1 DOT v2; // Actually operator^ 25 | v3 = v1 CROSS v2; // Actually operator% 26 | 27 | float f = v1[0]; // Subscript 28 | float *fp = v1; // Implicit conversion to float * 29 | 30 | f = len(v1); // Length (also len2 == squared length) 31 | f = dist(p1, p2); // Distance (also dist2 == squared distance) 32 | normalize(v1); // Normalize (i.e., make it unit length) 33 | // normalize(vec(0,0,0)) => vec(1,0,0) 34 | 35 | cout << v1 << endl; // iostream output in the form (1,2,3) 36 | cin >> v2; // iostream input using the same syntax 37 | 38 | Also defines the utility functions sqr, cube, sgn, swap, 39 | fract, clamp, mix, step, smoothstep, and trinorm 40 | */ 41 | 42 | 43 | // Windows defines these as macros, which prevents us from using the 44 | // type-safe versions from std::, as well as interfering with method defns 45 | #undef min 46 | #undef max 47 | 48 | 49 | #include 50 | #include 51 | #include 52 | using std::min; 53 | using std::max; 54 | using std::swap; 55 | using std::sqrt; 56 | class CPoint3D; 57 | 58 | 59 | // Let gcc optimize conditional branches a bit better... 60 | #ifndef likely 61 | # if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 62 | # define likely(x) (x) 63 | # define unlikely(x) (x) 64 | # else 65 | # define likely(x) (__builtin_expect((x), 1)) 66 | # define unlikely(x) (__builtin_expect((x), 0)) 67 | # endif 68 | #endif 69 | 70 | 71 | // Boost-like compile-time assertion checking 72 | template struct VEC_STATIC_ASSERTION_FAILURE; 73 | template <> struct VEC_STATIC_ASSERTION_FAILURE 74 | { void operator () () {} }; 75 | #define VEC_STATIC_CHECK(expr) VEC_STATIC_ASSERTION_FAILURE() 76 | 77 | 78 | 79 | namespace trimeshVec { 80 | 81 | template 82 | class Vec { 83 | private: 84 | _Tp v[D]; 85 | 86 | public: 87 | // Constructor for no arguments. Everything initialized to 0. 88 | Vec() { for (int i = 0; i < D; i++) v[i] = _Tp(0); } 89 | 90 | // Constructors for 2-4 arguments 91 | Vec(_Tp x, _Tp y) 92 | { VEC_STATIC_CHECK(D == 2); v[0] = x; v[1] = y; } 93 | Vec(_Tp x, _Tp y, _Tp z) 94 | { VEC_STATIC_CHECK(D == 3); v[0] = x; v[1] = y; v[2] = z; } 95 | Vec(_Tp x, _Tp y, _Tp z, _Tp w) 96 | { VEC_STATIC_CHECK(D == 4); v[0] = x; v[1] = y; v[2] = z; v[3] = w; } 97 | // [12/27/2009 maxint] 98 | template 99 | Vec(const Vec &x) 100 | { 101 | for (int i=0; i 106 | Vec(const Vec &x) 107 | { 108 | VEC_STATIC_CHECK(D2>=D); 109 | for (int i=0; i explicit Vec(const S &x) 125 | { for (int i = 0; i < D; i++) v[i] = _Tp(x[i]); } 126 | 127 | // No destructor or assignment operator needed 128 | 129 | // Array reference and conversion to pointer - no bounds checking 130 | const _Tp &operator [] (int i) const 131 | { return v[i]; } 132 | _Tp &operator [] (int i) 133 | { return v[i]; } 134 | operator const _Tp * () const 135 | { return v; } 136 | operator const _Tp * () 137 | { return v; } 138 | operator _Tp * () 139 | { return v; } 140 | 141 | // Member operators 142 | Vec &operator += (const Vec &x) 143 | { for (int i = 0; i < D; i++) v[i] += x[i]; return *this; } 144 | Vec &operator -= (const Vec &x) 145 | { for (int i = 0; i < D; i++) v[i] -= x[i]; return *this; } 146 | Vec &operator *= (const Vec &x) 147 | { for (int i = 0; i < D; i++) v[i] *= x[i]; return *this; } 148 | Vec &operator *= (const _Tp &x) 149 | { for (int i = 0; i < D; i++) v[i] *= x; return *this; } 150 | Vec &operator /= (const Vec &x) 151 | { for (int i = 0; i < D; i++) v[i] /= x[i]; return *this; } 152 | Vec &operator /= (const _Tp &x) 153 | { for (int i = 0; i < D; i++) v[i] /= x; return *this; } 154 | 155 | // [12/28/2009 maxint] 156 | template 157 | const Vec operator = (const Vec &x) 158 | { 159 | for (int i=0; i> 165 | 166 | // Some partial compatibility with valarrays and vectors 167 | typedef _Tp value_type; 168 | size_t size() const 169 | { return D; } 170 | _Tp sum() const 171 | { _Tp total = v[0]; 172 | for (int i = 1; i < D; i++) total += v[i]; 173 | return total; } 174 | _Tp avg() const 175 | { return sum() / D; } 176 | _Tp product() const 177 | { _Tp total = v[0]; 178 | for (int i = 1; i < D; i++) total *= v[i]; 179 | return total; } 180 | _Tp min() const 181 | { _Tp m = v[0]; 182 | for (int i = 0; i < D; i++) 183 | if (v[i] < m) m = v[i]; 184 | return m; } 185 | _Tp max() const 186 | { _Tp m = v[0]; 187 | for (int i = 1; i < D; i++) 188 | if (v[i] > m) m = v[i]; 189 | return m; } 190 | _Tp *begin() { return &(v[0]); } 191 | const _Tp *begin() const { return &(v[0]); } 192 | _Tp *end() { return begin() + D; } 193 | const _Tp *end() const { return begin() + D; } 194 | void clear() { for (int i = 0; i < D; i++) v[i] = _Tp(0); } 195 | bool empty() const 196 | { for (int i = 0; i < D; i++) 197 | if (v[i]) return false; 198 | return true; } 199 | // [12/27/2009 maxint] 200 | Vec normed() const 201 | { 202 | Vec res = (*this); 203 | _Tp sum = v[0] * v[0]; 204 | for (int i = 1; i < D; i++) 205 | sum += v[i] * v[i]; 206 | sum = sqrt(sum); 207 | for (int i=0; i& norm() 212 | { 213 | _Tp sum = v[0] * v[0]; 214 | for (int i = 1; i < D; i++) 215 | sum += v[i] * v[i]; 216 | sum = sqrt(sum); 217 | for (int i=0; i vec; 232 | typedef Vec<3,float> point; 233 | typedef Vec<2,float> vec2; 234 | typedef Vec<3,float> vec3; 235 | typedef Vec<4,float> vec4; 236 | typedef Vec<2,int> ivec2; 237 | typedef Vec<3,int> ivec3; 238 | typedef Vec<4,int> ivec4; 239 | 240 | 241 | // Nonmember operators that take two Vecs 242 | template 243 | static inline const Vec operator + (const Vec &v1, const Vec &v2) 244 | { 245 | return Vec(v1) += v2; 246 | } 247 | 248 | template 249 | static inline const Vec operator - (const Vec &v1, const Vec &v2) 250 | { 251 | return Vec(v1) -= v2; 252 | } 253 | 254 | template 255 | static inline const Vec operator * (const Vec &v1, const Vec &v2) 256 | { 257 | return Vec(v1) *= v2; 258 | } 259 | 260 | template 261 | static inline const Vec operator / (const Vec &v1, const Vec &v2) 262 | { 263 | return Vec(v1) /= v2; 264 | } 265 | 266 | #define DOT ^ 267 | template 268 | static inline const _Tp operator ^ (const Vec &v1, const Vec &v2) 269 | { 270 | _Tp sum = v1[0] * v2[0]; 271 | for (int i = 1; i < D; i++) 272 | sum += v1[i] * v2[i]; 273 | return sum; 274 | } 275 | template 276 | static inline const _Tp operator ^ (const Vec<3,_Tp> &v1, const Vec<4,_Tp> &v2) 277 | { 278 | _Tp sum = v1[0] * v2[0]; 279 | for (int i = 1; i < 3; i++) 280 | sum += v1[i] * v2[i]; 281 | return sum; 282 | } 283 | template 284 | static inline const _Tp operator ^ (const Vec<4,_Tp> &v1, const Vec<3,_Tp> &v2) 285 | { 286 | return (v2 DOT v1); 287 | } 288 | 289 | #define CROSS % 290 | template 291 | static inline const Vec<3,_Tp> operator % (const Vec<3,_Tp> &v1, const Vec<3,_Tp> &v2) 292 | { 293 | return Vec<3,_Tp>(v1[1]*v2[2] - v1[2]*v2[1], 294 | v1[2]*v2[0] - v1[0]*v2[2], 295 | v1[0]*v2[1] - v1[1]*v2[0]); 296 | } 297 | template 298 | static inline const Vec<3,_Tp> operator % (const Vec<4,_Tp> &v1, const Vec<4,_Tp> &v2) 299 | { 300 | return Vec<3,_Tp>(v1[1]*v2[2] - v1[2]*v2[1], 301 | v1[2]*v2[0] - v1[0]*v2[2], 302 | v1[0]*v2[1] - v1[1]*v2[0]); 303 | } 304 | 305 | // Component-wise equality and inequality (#include the usual caveats 306 | // about comparing floats for equality...) 307 | template 308 | static inline bool operator == (const Vec &v1, const Vec &v2) 309 | { 310 | for (int i = 0; i < D; i++) 311 | if (v1[i] != v2[i]) 312 | return false; 313 | return true; 314 | } 315 | 316 | template 317 | static inline bool operator != (const Vec &v1, const Vec &v2) 318 | { 319 | for (int i = 0; i < D; i++) 320 | if (v1[i] != v2[i]) 321 | return true; 322 | return false; 323 | } 324 | 325 | 326 | // Unary operators 327 | template 328 | static inline const Vec &operator + (const Vec &v) 329 | { 330 | return v; 331 | } 332 | 333 | template 334 | static inline const Vec operator - (const Vec &v) 335 | { 336 | Vec result(v); 337 | for (int i = 0; i < D; i++) 338 | result[i] = -result[i]; 339 | return result; 340 | } 341 | 342 | template 343 | static inline bool operator ! (const Vec &v) 344 | { 345 | return v.empty(); 346 | } 347 | 348 | 349 | // Vec/scalar operators 350 | template 351 | static inline const Vec operator * (const _Tp &x, const Vec &v) 352 | { 353 | Vec result(v); 354 | for (int i = 0; i < D; i++) 355 | result[i] = x * result[i]; 356 | return result; 357 | } 358 | 359 | template 360 | static inline const Vec operator * (const Vec &v, const _Tp &x) 361 | { 362 | return Vec(v) *= x; 363 | } 364 | 365 | template 366 | static inline const Vec operator / (const _Tp &x, const Vec &v) 367 | { 368 | Vec result(v); 369 | for (int i = 0; i < D; i++) 370 | result[i] = x / result[i]; 371 | return result; 372 | } 373 | 374 | template 375 | static inline const Vec operator / (const Vec &v, const _Tp &x) 376 | { 377 | return Vec(v) /= x; 378 | } 379 | 380 | 381 | // iostream operators 382 | template 383 | static inline std::ostream &operator << (std::ostream &os, const Vec &v) 384 | 385 | { 386 | os << "("; 387 | for (int i = 0; i < D-1; i++) 388 | os << v[i] << ", "; 389 | return os << v[D-1] << ")"; 390 | } 391 | 392 | template 393 | static inline std::istream &operator >> (std::istream &is, Vec &v) 394 | { 395 | char c1 = 0, c2 = 0; 396 | 397 | is >> c1; 398 | if (c1 == '(' || c1 == '[') { 399 | is >> v[0] >> std::ws >> c2; 400 | for (int i = 1; i < D; i++) { 401 | if (c2 == ',') 402 | is >> v[i] >> std::ws >> c2; 403 | else 404 | is.setstate(std::ios::failbit); 405 | } 406 | } 407 | 408 | if (c1 == '(' && c2 != ')') 409 | is.setstate(std::ios::failbit); 410 | else if (c1 == '[' && c2 != ']') 411 | is.setstate(std::ios::failbit); 412 | 413 | return is; 414 | } 415 | 416 | 417 | // Utility functions for square and cube, to go along with sqrt and cbrt 418 | template 419 | static inline _Tp sqr(const _Tp &x) 420 | { 421 | return x*x; 422 | } 423 | 424 | template 425 | static inline _Tp cube(const _Tp &x) 426 | { 427 | return x*x*x; 428 | } 429 | 430 | 431 | // Utility functions based on GLSL 432 | template 433 | static inline _Tp fract(const _Tp &x) 434 | { 435 | return x - floor(x); 436 | } 437 | 438 | template 439 | static inline _Tp clamp(const _Tp &x, const _Tp &a, const _Tp &b) 440 | { 441 | return x > a ? x < b ? x : b : a; // returns a on NaN 442 | } 443 | 444 | template 445 | static inline _Tp mix(const _Tp &x, const _Tp &y, const S &a) 446 | { 447 | return (S(1)-a) * x + a * y; 448 | } 449 | 450 | template 451 | static inline _Tp step(const _Tp &x, const _Tp &a) 452 | { 453 | return x < a ? _Tp(0) : _Tp(1); 454 | } 455 | 456 | template 457 | static inline _Tp smoothstep(const _Tp &x, const _Tp &a, const _Tp &b) 458 | { 459 | if (b <= a) return step(x,a); 460 | _Tp t = (x - a) / (b - a); 461 | return t <= _Tp(0) ? _Tp(0) : t >= _Tp(1) ? _Tp(1) : t * t * (_Tp(3) - _Tp(2) * t); 462 | } 463 | 464 | // Area-weighted triangle face normal 465 | template 466 | static inline _Tp trinorm(const _Tp &v0, const _Tp &v1, const _Tp &v2) 467 | { 468 | return (typename _Tp::value_type) 0.5 * ((v1 - v0) CROSS (v2 - v0)); 469 | } 470 | 471 | // Sign of a scalar 472 | template 473 | static inline _Tp sgn(const _Tp &x) 474 | { 475 | return (x < _Tp(0)) ? _Tp(-1) : _Tp(1); 476 | } 477 | 478 | 479 | // Functions on Vecs 480 | template 481 | static inline const _Tp len2(const Vec &v) 482 | { 483 | _Tp l2 = v[0] * v[0]; 484 | for (int i = 1; i < D; i++) 485 | l2 += v[i] * v[i]; 486 | return l2; 487 | } 488 | 489 | template 490 | static inline const _Tp len(const Vec &v) 491 | { 492 | return sqrt(len2(v)); 493 | } 494 | 495 | template 496 | static inline const _Tp dist2(const Vec &v1, const Vec &v2) 497 | { 498 | _Tp d2 = sqr(v2[0]-v1[0]); 499 | for (int i = 1; i < D; i++) 500 | d2 += sqr(v2[i]-v1[i]); 501 | return d2; 502 | } 503 | 504 | template 505 | static inline const _Tp dist(const Vec &v1, const Vec &v2) 506 | { 507 | return sqrt(dist2(v1,v2)); 508 | } 509 | 510 | template 511 | static inline Vec normalize(Vec &v) 512 | { 513 | _Tp l = len(v); 514 | if (unlikely(l <= _Tp(0))) { 515 | v[0] = _Tp(1); 516 | for (int i = 1; i < D; i++) 517 | v[i] = _Tp(0); 518 | return v; 519 | } 520 | 521 | l = _Tp(1) / l; 522 | for (int i = 0; i < D; i++) 523 | v[i] *= l; 524 | 525 | return v; 526 | } 527 | 528 | template 529 | static inline void swap(const Vec &v1, const Vec &v2) 530 | { 531 | for (int i = 0; i < D; i++) 532 | swap(v1[i], v2[i]); 533 | } 534 | 535 | template 536 | static inline Vec fabs(const Vec &v) 537 | { 538 | Vec result(v); 539 | for (int i = 0; i < D; i++) 540 | if (result[i] < _Tp(0)) 541 | result[i] = -result[i]; 542 | return result; 543 | } 544 | } 545 | 546 | #endif 547 | -------------------------------------------------------------------------------- /VectOps.cpp: -------------------------------------------------------------------------------- 1 | #include "VectOps.h" 2 | #include 3 | 4 | // m1, m2 and m3 are 16-vectors representing 4x4 matrices 5 | void VectOps::mmMult(double m1[16], double m2[16], double m3[16]) 6 | { 7 | //var i:int, j:int, k:int; 8 | int i, j, k; 9 | for(i=0; i<4; i++) 10 | for(j=0; j<4; j++) 11 | { 12 | m3[j*4+i] = 0; 13 | for(k=0; k<4; k++) 14 | m3[j*4+i] += m1[k*4+i]*m2[j*4+k]; 15 | } 16 | } 17 | 18 | // m1, m2 and m3 are 9-vectors representing 3x3 matrices 19 | void VectOps::mmMult3x3(double m1[9], double m2[9], double m3[9]) 20 | { 21 | //var i:int, j:int, k:int; 22 | int i, j, k; 23 | for(i=0; i<3; i++) 24 | for(j=0; j<3; j++) 25 | { 26 | m3[j*3+i] = 0; 27 | for(k=0; k<3; k++) 28 | m3[j*3+i] += m1[k*3+i]*m2[j*3+k]; 29 | } 30 | } 31 | 32 | // 33 | void VectOps::twist_to_mat(double omega[3], double theta, double rm[16]) 34 | { 35 | double omega_hat[16] = {0, omega[2], -omega[1], 0, 36 | -omega[2], 0, omega[0], 0, 37 | omega[1], -omega[0], 0, 0, 38 | 0, 0, 0, 1}; 39 | double unit[16] = {1, 0, 0, 0, 40 | 0, 1, 0, 0, 41 | 0, 0, 1, 0, 42 | 0, 0, 0, 1}; 43 | double omega_square[16];//:Array = new Array(16); 44 | //double temprm[16]; 45 | double sinth, costh; 46 | int i; 47 | mmMult(omega_hat, omega_hat, omega_square); 48 | sinth= sin(theta); 49 | costh= cos(theta); 50 | for(i=0; i< 16; i++) 51 | rm[i]= unit[i] + omega_hat[i]*sinth + omega_square[i]*(1-costh); 52 | rm[15]= 1; 53 | // for (i = 0; i < 3; i++) 54 | // for (int j = 0; j < 3; j++) 55 | // { 56 | // rm[3*i + j] = temprm[4*i + j]; 57 | // } 58 | 59 | // 60 | // omega_hat = unit = omega_square = null; 61 | } 62 | // vs and vd are 4-vectors 63 | void VectOps::mvMult(double m[16], double vs[4], double vd[4]) 64 | { 65 | //var i:int, j:int; 66 | int i, j; 67 | for(i=0; i<4; i++) 68 | { 69 | vd[i]=0; 70 | for(j=0; j<4; j++) 71 | vd[i] += m[j*4+i]*vs[j]; 72 | } 73 | } 74 | 75 | // vs and vd are 3-vectors 76 | void VectOps::mvMult3x3(double m[9], double vs[3], double vd[3]) 77 | { 78 | //var i:int, j:int; 79 | int i, j; 80 | for(i=0; i<3; i++) 81 | { 82 | vd[i]=0; 83 | for(j=0; j<3; j++) 84 | vd[i] += m[j*3+i]*vs[j]; 85 | } 86 | } 87 | 88 | void VectOps::mmAdd(double m1[9], double m2[9], double m3[9]) 89 | { 90 | for (int i = 0; i < 9; i++) 91 | { 92 | m3[i] = m1[i] + m2[i]; 93 | } 94 | } 95 | 96 | void VectOps::mmMinus(double m1[9], double m2[9], double m3[9]) 97 | { 98 | for (int i = 0; i < 9; i++) 99 | { 100 | m3[i] = m1[i] - m2[i]; 101 | } 102 | } 103 | 104 | void VectOps::mscale(double scale, double m1[9], double m2[9]) 105 | { 106 | for (int i = 0; i < 9; i++) 107 | { 108 | m2[i] = scale * m1[i]; 109 | } 110 | } 111 | 112 | void VectOps::Transpose(double m1[9], double m2[9]) 113 | { 114 | for (int i = 0; i < 3; i++) 115 | for (int j = 0; j < 3; j++) 116 | { 117 | m2[i*3 + j] = m1[j *3 +i]; 118 | } 119 | } 120 | 121 | void VectOps::vec2mat(const Vec3d& v, double m[9]) 122 | { 123 | for (int i = 0; i < 3; i++) 124 | { 125 | m[0] = v[0] * v[0]; 126 | m[1] = m[3] = v[0] * v[1]; 127 | m[2] = m[6] = v[0] * v[2]; 128 | m[4] = v[1] * v[1]; 129 | m[5] = m[7] = v[1] * v[2]; 130 | m[8] = v[2] * v[2]; 131 | } 132 | } -------------------------------------------------------------------------------- /VectOps.h: -------------------------------------------------------------------------------- 1 | #ifndef __VECTOPS_H_ 2 | #define __VECTOPS_H_ 3 | 4 | #include "MathDefs.h" 5 | 6 | class VectOps 7 | { 8 | public: 9 | ////////////////////////////////////////////// 10 | /*4x4 matrix m[16] structure 11 | 0 4 8 12 12 | 1 5 9 13 13 | 2 6 10 14 14 | 3 7 11 15 15 | */ 16 | 17 | void static twist_to_mat(double omega[3], double theta, double rm[16]); 18 | 19 | void static mmMult(double m1[16], double m2[16], double m3[16] ); 20 | 21 | void static mvMult(double m[16], double vs[4], double vd[4]); 22 | void static mvMult3x3(double m[9], double vs[3], double vd[3]); 23 | 24 | void static mmMult3x3(double m1[9], double m2[9], double m3[9]); 25 | 26 | void static mmAdd(double m1[9], double m2[9], double m3[9]); 27 | void static mmMinus(double m1[9], double m2[9], double m3[9]); 28 | void static mscale(double scale, double m1[9], double m2[9]); 29 | 30 | void static Transpose(double m1[9], double m2[9]); 31 | void static vec2mat(const Vec3d& v, double m[9]); //compute vT * v, v is 3dimension, m is a 3x3 matrix 32 | }; 33 | 34 | #endif //__VECTOPS_H_ -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mainwindow.h" 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | Q_INIT_RESOURCE(sdi); 7 | QApplication app(argc, argv); 8 | 9 | MainWindow win; 10 | win.show(); 11 | 12 | return app.exec(); 13 | } -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "AccessObj.h" 3 | #include "ScanLine.h" 4 | #include 5 | #include 6 | 7 | const QString WIDGET_NAME = "ImageView"; 8 | const QString WINDOW_TITLE = "CG ZBuffer"; 9 | const Vec3d EYE_POS(3, 4, 5); 10 | const Vec4d LIGHT_POS(2, 3, 4, 1); 11 | 12 | MainWindow::MainWindow() 13 | : mImage(800, 600, QImage::Format_ARGB32) 14 | , mpAccessObj(0) 15 | , mpRenderSystem(0) 16 | { 17 | init(); 18 | } 19 | 20 | MainWindow::MainWindow(const QString &fileName) 21 | : mImage(800, 600, QImage::Format_ARGB32) 22 | , mpAccessObj(0) 23 | , mpRenderSystem(0) 24 | { 25 | init(); 26 | if (QFile::exists(fileName)) 27 | { 28 | openObjFile(fileName); 29 | statusBar()->showMessage(tr("File loaded"), 3000); 30 | } 31 | else 32 | { 33 | statusBar()->showMessage(tr("File load fail")); 34 | } 35 | } 36 | 37 | MainWindow::~MainWindow() 38 | { 39 | SAFE_DELETE(mpAccessObj); 40 | SAFE_DELETE(mpRenderSystem); 41 | } 42 | 43 | void MainWindow::init() 44 | { 45 | srand((unsigned int)time(0)); 46 | xRot = yRot = zRot = 30; 47 | 48 | initRenderSystem(); 49 | 50 | setupUi(); 51 | createActions(); 52 | createMenus(); 53 | createToolBars(); 54 | createStatusBar(); 55 | 56 | renderObj(); 57 | //rotateBy(0, 0, 0); 58 | } 59 | 60 | void MainWindow::initRenderSystem() 61 | { 62 | mpAccessObj = new CAccessObj; 63 | mImage.fill(qRgb(200, 200, 200)); 64 | mpRenderSystem = new CScanLine(mImage.width(), mImage.height(), &mImage); 65 | 66 | // set camera 67 | Vec3d at(0, 0, 0); 68 | Vec3d up(0, 1, 0); 69 | mpRenderSystem->lookAt(EYE_POS, at, up); 70 | mpRenderSystem->perspective(3.14/6, mImage.width()*1.0/mImage.height(), 1, 100); 71 | //mpRenderSystem.ortho(-2, 2, -2, 2, 1, 100); 72 | 73 | // set light 74 | mpRenderSystem->mLight.type = SL_LIGHT_POINT; 75 | //lit.type = SL_LIGHT_DIRECTIONAL; 76 | mpRenderSystem->mLight.direction = Vec3d(-1.0, -1.0, -0.5); 77 | //lit.position = Vec4d(3, 4, 5, 1); 78 | mpRenderSystem->mLight.position = LIGHT_POS; 79 | 80 | mpRenderSystem->mMaterial.specular = Color4d(1.0, 1.0, 1.0, 1.0); 81 | mpRenderSystem->mMaterial.shiness = 60; 82 | } 83 | 84 | void MainWindow::setupUi() 85 | { 86 | mImgView = new QWidget; 87 | mImgView->setObjectName(WIDGET_NAME); 88 | mImgView->setFixedSize(mImage.size()); 89 | this->setCentralWidget(mImgView); 90 | mImgView->installEventFilter(this); 91 | this->layout()->setSizeConstraint(QLayout::SetFixedSize); 92 | 93 | setWindowTitle(WINDOW_TITLE); 94 | } 95 | 96 | QSize MainWindow::sizeHint() const 97 | { 98 | return mImage.size(); 99 | } 100 | 101 | void MainWindow::createActions() 102 | { 103 | mOpenAct = new QAction(QIcon(":/images/open.png"), tr("&Open Obj..."), this); 104 | mOpenAct->setShortcut(QKeySequence::Open); 105 | mOpenAct->setStatusTip(tr("Open an obj model file")); 106 | connect(mOpenAct, SIGNAL(triggered()), this, SLOT(open())); 107 | 108 | mSaveAsImageAct = new QAction(QIcon(":/images/save.png"), tr("&Save As Image..."), this); 109 | mSaveAsImageAct->setShortcut(QKeySequence::Save); 110 | mSaveAsImageAct->setStatusTip(tr("Save the result as an image")); 111 | connect(mSaveAsImageAct, SIGNAL(triggered()), this, SLOT(saveAs())); 112 | 113 | mQuitAct = new QAction(tr("&Quit"), this); 114 | mQuitAct->setShortcut(tr("Ctrl+Q")); 115 | mQuitAct->setStatusTip(tr("Exit the application")); 116 | connect(mQuitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); 117 | 118 | mResolutionAct = new QAction(tr("Set &Canvas..."), this); 119 | mResolutionAct->setShortcut(tr("Ctrl+C")); 120 | mResolutionAct->setStatusTip(tr("Set the resolution")); 121 | connect(mResolutionAct, SIGNAL(triggered()), this, SLOT(resolution())); 122 | 123 | // shading actions 124 | mShadeFlatAct = new QAction(tr("&Flat Shading"), this); 125 | mShadeFlatAct->setStatusTip(tr("Per vertex shading model (e.g. Gouraud Shading )")); 126 | mShadeFlatAct->setCheckable(true); 127 | mShadeFlatAct->setChecked(mpRenderSystem->renderState().isFlatShading()); 128 | 129 | mShadeSmoothAct = new QAction(tr("&Smooth Shading"), this); 130 | mShadeSmoothAct->setStatusTip(tr("Per pixel shading model (e.g. Phong Shading )")); 131 | mShadeSmoothAct->setCheckable(true); 132 | mShadeSmoothAct->setChecked(mpRenderSystem->renderState().isSmoothShading() ); 133 | 134 | // lighting actions 135 | mToggleLightingAct = new QAction(tr("&Lighting"), this); 136 | mToggleLightingAct->setStatusTip(tr("Enable/Disable lighting")); 137 | mToggleLightingAct->setCheckable(true); 138 | mToggleLightingAct->setChecked(mpRenderSystem->renderState().isLighting()); 139 | 140 | mRandomColorAct = new QAction(tr("&Random Color"), this); 141 | mRandomColorAct->setStatusTip(tr("Enable/Disable generating random color")); 142 | mRandomColorAct->setCheckable(true); 143 | mRandomColorAct->setChecked(true); 144 | 145 | mPointLightAct = new QAction(tr("&Point Light"), this); 146 | mPointLightAct->setStatusTip(tr("Choose point light")); 147 | mPointLightAct->setCheckable(true); 148 | mPointLightAct->setChecked(mpRenderSystem->mLight.type == SL_LIGHT_POINT); 149 | 150 | mDirLightAct = new QAction(tr("&Dir Light"), this); 151 | mDirLightAct->setStatusTip(tr("Choose directional light")); 152 | mDirLightAct->setCheckable(true); 153 | mDirLightAct->setChecked(mpRenderSystem->mLight.type == SL_LIGHT_DIRECTIONAL); 154 | 155 | mShadeActGroup = new QActionGroup(this); 156 | mShadeActGroup->setExclusive(false); 157 | mShadeActGroup->addAction(mShadeFlatAct); 158 | mShadeActGroup->addAction(mShadeSmoothAct); 159 | mShadeActGroup->addAction(mToggleLightingAct); 160 | mShadeActGroup->addAction(mRandomColorAct); 161 | mShadeActGroup->addAction(mPointLightAct); 162 | mShadeActGroup->addAction(mDirLightAct); 163 | connect(mShadeActGroup, SIGNAL(triggered(QAction*)), this, SLOT(shadeModel(QAction*))); 164 | 165 | // view menu 166 | mViewToolBarAct = new QAction(tr("&Toolbar"), this); 167 | mViewToolBarAct->setStatusTip(tr("Toggle toolbar")); 168 | mViewToolBarAct->setCheckable(true); 169 | mViewToolBarAct->setChecked(true); 170 | mViewToolBarAct->setShortcut(tr("Ctrl+T")); 171 | 172 | mViewActGroup = new QActionGroup(this); 173 | mViewActGroup->addAction(mViewToolBarAct); 174 | mViewActGroup->setExclusive(false); 175 | connect(mViewActGroup, SIGNAL(triggered(QAction*)), this, SLOT(toggleView(QAction*))); 176 | 177 | // help menu 178 | mAboutAct = new QAction(tr("&About"), this); 179 | mAboutAct->setStatusTip(tr("Show the application's About box")); 180 | connect(mAboutAct, SIGNAL(triggered()), this, SLOT(about())); 181 | mAboutQtAct = new QAction(tr("About &Qt"), this); 182 | mAboutQtAct->setStatusTip(tr("Show the Qt library's About box")); 183 | connect(mAboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); 184 | 185 | // mouse operation 186 | mMouseOpAct = new QAction(tr("&Mouse Op"), this); 187 | mMouseOpAct->setStatusTip(tr("Change camera position with mouse")); 188 | mMouseOpAct->setCheckable(true); 189 | mMouseOpAct->setChecked(true); 190 | mMouseOpAct->setShortcut(tr("Ctrl+M")); 191 | } 192 | 193 | void MainWindow::shadeModel(QAction* act) 194 | { 195 | if (act == mShadeFlatAct) 196 | { 197 | mpRenderSystem->setRenderState(SL_SHADE_FLAT, true); 198 | mShadeFlatAct->setChecked(true); 199 | mShadeSmoothAct->setChecked(false); 200 | statusBar()->showMessage(tr("Flat shading finished"), 3000); 201 | } 202 | else if (act == mShadeSmoothAct) 203 | { 204 | mpRenderSystem->setRenderState(SL_SHADE_SMOOTH, true); 205 | mShadeSmoothAct->setChecked(true); 206 | mShadeFlatAct->setChecked(false); 207 | statusBar()->showMessage(tr("Smooth shading finished"), 3000); 208 | } 209 | else if (act == mToggleLightingAct) 210 | { 211 | mpRenderSystem->setRenderState(SL_LIGHTING, mToggleLightingAct->isChecked()); 212 | statusBar()->showMessage(mToggleLightingAct->isChecked() ? tr("Enabled lighting") : 213 | tr("Disabled lighting"), 3000); 214 | } 215 | else if (act == mRandomColorAct) 216 | { 217 | if (act->isChecked()) 218 | statusBar()->showMessage(tr("Random color generated"), 3000); 219 | else 220 | statusBar()->showMessage(tr("Disable random color generation"), 3000); 221 | } 222 | else if (act == mPointLightAct) 223 | { 224 | act->setChecked(true); 225 | mDirLightAct->setChecked(false); 226 | mpRenderSystem->mLight.type = SL_LIGHT_POINT; 227 | statusBar()->showMessage(tr("Point lighting"), 3000); 228 | } 229 | else if (act == mDirLightAct) 230 | { 231 | act->setChecked(true); 232 | mPointLightAct->setChecked(false); 233 | mpRenderSystem->mLight.type = SL_LIGHT_DIRECTIONAL; 234 | statusBar()->showMessage(tr("Directional lighting"), 3000); 235 | } 236 | else 237 | { 238 | statusBar()->showMessage(tr("Invalid operation"), 3000); 239 | return; 240 | } 241 | 242 | renderObj(); 243 | } 244 | 245 | void MainWindow::toggleView(QAction *act) 246 | { 247 | if (act == mViewToolBarAct) 248 | { 249 | bool bShow = act->isChecked(); 250 | mFileToolBar->setVisible(bShow); 251 | mEditToolBar->setVisible(bShow); 252 | } 253 | } 254 | 255 | void MainWindow::createMenus() 256 | { 257 | mFileMenu = menuBar()->addMenu(tr("&File")); 258 | mFileMenu->addAction(mOpenAct); 259 | mFileMenu->addAction(mSaveAsImageAct); 260 | mFileMenu->addSeparator(); 261 | mFileMenu->addAction(mQuitAct); 262 | 263 | menuBar()->addSeparator(); 264 | 265 | mViewMenu = menuBar()->addMenu(tr("&View")); 266 | mViewMenu->addAction(mViewToolBarAct); 267 | 268 | menuBar()->addSeparator(); 269 | 270 | mEditMenu = menuBar()->addMenu(tr("&Edit")); 271 | mEditMenu->addAction(mResolutionAct); 272 | mEditMenu->addAction(mRandomColorAct); 273 | mEditMenu->addSeparator(); 274 | mEditMenu->addAction(mToggleLightingAct); 275 | mEditMenu->addAction(mPointLightAct); 276 | mEditMenu->addAction(mDirLightAct); 277 | mEditMenu->addSeparator(); 278 | mEditMenu->addAction(mShadeFlatAct); 279 | mEditMenu->addAction(mShadeSmoothAct); 280 | 281 | menuBar()->addSeparator(); 282 | mHelpMenu = menuBar()->addMenu(tr("&Help")); 283 | mHelpMenu->addAction(mAboutAct); 284 | mHelpMenu->addAction(mAboutQtAct); 285 | } 286 | 287 | void MainWindow::createToolBars() 288 | { 289 | mFileToolBar = addToolBar(tr("File")); 290 | mFileToolBar->addAction(mOpenAct); 291 | mFileToolBar->addAction(mSaveAsImageAct); 292 | 293 | mEditToolBar = addToolBar(tr("Edit")); 294 | mEditToolBar->addAction(mResolutionAct); 295 | mEditToolBar->addAction(mRandomColorAct); 296 | mEditToolBar->addSeparator(); 297 | mEditToolBar->addAction(mToggleLightingAct); 298 | mEditToolBar->addAction(mPointLightAct); 299 | mEditToolBar->addAction(mDirLightAct); 300 | mEditToolBar->addSeparator(); 301 | mEditToolBar->addAction(mShadeFlatAct); 302 | mEditToolBar->addAction(mShadeSmoothAct); 303 | 304 | // camera and light toolbar 305 | mSpinEyeX = new QDoubleSpinBox; 306 | mSpinEyeY = new QDoubleSpinBox; 307 | mSpinEyeZ = new QDoubleSpinBox; 308 | mSpinLightX = new QDoubleSpinBox; 309 | mSpinLightY = new QDoubleSpinBox; 310 | mSpinLightZ = new QDoubleSpinBox; 311 | mSpinEyeX->setMinimum(-100.0); 312 | mSpinEyeY->setMinimum(-100.0); 313 | mSpinEyeZ->setMinimum(-100.0); 314 | mSpinLightX->setMinimum(-100.0); 315 | mSpinLightY->setMinimum(-100.0); 316 | mSpinLightX->setMinimum(-100.0); 317 | mSpinEyeX->setSingleStep(0.2); 318 | mSpinEyeY->setSingleStep(0.2); 319 | mSpinEyeZ->setSingleStep(0.2); 320 | mSpinLightX->setSingleStep(0.2); 321 | mSpinLightY->setSingleStep(0.2); 322 | mSpinLightZ->setSingleStep(0.2); 323 | mSpinEyeX->setValue(EYE_POS[0]); 324 | mSpinEyeY->setValue(EYE_POS[1]); 325 | mSpinEyeZ->setValue(EYE_POS[2]); 326 | mSpinLightX->setValue(LIGHT_POS[0]); 327 | mSpinLightY->setValue(LIGHT_POS[1]); 328 | mSpinLightZ->setValue(LIGHT_POS[2]); 329 | 330 | mCameraLightToolBar = addToolBar(tr("CameraAndLight")); 331 | addToolBar(Qt::BottomToolBarArea, mCameraLightToolBar); 332 | mCameraLightToolBar->setToolTip(tr("Set position of camera or light")); 333 | 334 | mCameraLightToolBar->addWidget(new QLabel(tr("Camera "))); 335 | mCameraLightToolBar->addWidget(new QLabel(tr("x:"))); 336 | mCameraLightToolBar->addWidget(mSpinEyeX); 337 | mCameraLightToolBar->addWidget(new QLabel(tr("y:"))); 338 | mCameraLightToolBar->addWidget(mSpinEyeY); 339 | mCameraLightToolBar->addWidget(new QLabel(tr("z:"))); 340 | mCameraLightToolBar->addWidget(mSpinEyeZ); 341 | mCameraLightToolBar->addSeparator(); 342 | mCameraLightToolBar->addWidget(new QLabel(tr("Light "))); 343 | mCameraLightToolBar->addWidget(new QLabel(tr("x:"))); 344 | mCameraLightToolBar->addWidget(mSpinLightX); 345 | mCameraLightToolBar->addWidget(new QLabel(tr("y:"))); 346 | mCameraLightToolBar->addWidget(mSpinLightY); 347 | mCameraLightToolBar->addWidget(new QLabel(tr("z:"))); 348 | mCameraLightToolBar->addWidget(mSpinLightZ); 349 | 350 | connect(mSpinEyeX, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 351 | connect(mSpinEyeY, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 352 | connect(mSpinEyeZ, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 353 | connect(mSpinLightX, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 354 | connect(mSpinLightY, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 355 | connect(mSpinLightZ, SIGNAL(valueChanged(double)), this, SLOT(newFrustumOrLight())); 356 | } 357 | 358 | void MainWindow::createStatusBar() 359 | { 360 | statusBar()->showMessage(tr("Ready")); 361 | } 362 | 363 | void MainWindow::open() 364 | { 365 | QString fileName = QFileDialog::getOpenFileName(this, 366 | tr("Open Obj Model"), "objs", tr("Obj Fils (*.obj)")); 367 | if (!fileName.isEmpty()) 368 | { 369 | openObjFile(fileName); 370 | } 371 | } 372 | 373 | void MainWindow::saveAs() 374 | { 375 | QString fileName = QFileDialog::getSaveFileName(this, 376 | tr("Save Result"), "res.png", tr("Images (*.png *.jpg *.bmp)")); 377 | 378 | saveAsImageFile(fileName); 379 | } 380 | 381 | void MainWindow::resolution() 382 | { 383 | bool ok; 384 | QString strSize = QInputDialog::getText(this, tr("Set Resolution"), 385 | tr("New Resolution (e.g. 800 600) : "), QLineEdit::Normal, 386 | tr("800 600"), &ok); 387 | 388 | int w = strSize.section(' ', 0, 0).toInt(); 389 | int h = strSize.section(' ', 1, 1).toInt(); 390 | if (ok && w>0 && h>0) 391 | { 392 | setResolution(w, h); 393 | mImgView->setFixedSize(mImage.size()); 394 | statusBar()->showMessage(tr("New resolution (%1, %2) is applied").arg(w).arg(h), 3000); 395 | } 396 | else 397 | { 398 | statusBar()->showMessage(tr("Invalid resolution"), 3000); 399 | } 400 | } 401 | 402 | void MainWindow::openObjFile(const QString& fileName) 403 | { 404 | if (mpAccessObj->LoadOBJ(fileName.toStdString().c_str())) 405 | { 406 | mpAccessObj->UnifiedModel(); 407 | 408 | renderObj(); 409 | 410 | setWindowTitle( tr("%1 - %2") 411 | .arg(strippedName(fileName)) 412 | .arg(WINDOW_TITLE) ); 413 | } 414 | else 415 | { 416 | QMessageBox::warning(this, tr("OBJ File Invalid"), 417 | tr("File %1 is not a valid obj model file.").arg(fileName)); 418 | } 419 | } 420 | 421 | void MainWindow::renderObj() 422 | { 423 | clock_t tt = clock(); 424 | 425 | mpRenderSystem->clear(SL_COLOR_BUFFER | SL_DEPTH_BUFFER, Color4u(200, 200, 200, 255), 1.0); 426 | if (mpAccessObj->m_pModel) 427 | { 428 | // clear frame buffer 429 | 430 | mpRenderSystem->begin(SL_TRIANGLES); 431 | CPoint3D *vpVertices = mpAccessObj->m_pModel->vpVertices; 432 | CPoint3D *vpNormals = mpAccessObj->m_pModel->vpNormals; 433 | if (!mRandomColorAct->isChecked()) 434 | mpRenderSystem->color3i(255, 255, 255); 435 | for (unsigned int i=0; im_pModel->nTriangles; ++i) 436 | { 437 | COBJtriangle &pTri = mpAccessObj->m_pModel->pTriangles[i]; 438 | if (mRandomColorAct->isChecked()) 439 | { 440 | byte iR = rand() % 256; 441 | byte iG = rand() % 256; 442 | byte iB = rand() % 256; 443 | mpRenderSystem->color3i(iR, iG, iB); 444 | } 445 | if (vpNormals) mpRenderSystem->normal3fv(vpNormals[pTri.nindices[0]]); 446 | mpRenderSystem->vertex3fv(vpVertices[pTri.vindices[0]]); 447 | if (vpNormals) mpRenderSystem->normal3fv(vpNormals[pTri.nindices[1]]); 448 | mpRenderSystem->vertex3fv(vpVertices[pTri.vindices[1]]); 449 | if (vpNormals) mpRenderSystem->normal3fv(vpNormals[pTri.nindices[2]]); 450 | mpRenderSystem->vertex3fv(vpVertices[pTri.vindices[2]]); 451 | } 452 | mpRenderSystem->end(); 453 | } 454 | else 455 | { 456 | drawCubeTest(); 457 | } 458 | 459 | statusBar()->showMessage(tr("Rendering finished in %1 ms. Triangles: %2") 460 | .arg(clock()-tt) 461 | .arg(mpAccessObj->m_pModel ? mpAccessObj->m_pModel->nTriangles : 12), 5000); 462 | 463 | mImgView->update(); 464 | } 465 | 466 | void MainWindow::saveAsImageFile(const QString& fileName) 467 | { 468 | mImage.save(fileName); 469 | } 470 | 471 | void MainWindow::setResolution(int width, int height) 472 | { 473 | mImage = mImage.scaled(width, height); 474 | mpRenderSystem->setRenderTarget(mImage.width(), mImage.height(), &mImage); 475 | mpRenderSystem->perspective(3.14/6, mImage.width()*1.0/mImage.height(), 1, 100); 476 | mpRenderSystem->clear(SL_DEPTH_BUFFER | SL_COLOR_BUFFER, Color4u(200, 200, 200, 255)); 477 | 478 | renderObj(); 479 | } 480 | 481 | void MainWindow::newFrustumOrLight() 482 | { 483 | // set camera 484 | Vec3d eye(mSpinEyeX->value(), mSpinEyeY->value(), mSpinEyeZ->value()); 485 | Vec3d at(0, 0, 0); 486 | Vec3d up(0, 1, 0); 487 | mpRenderSystem->lookAt(eye, at, up); 488 | mpRenderSystem->perspective(3.14/6, mImage.width()*1.0/mImage.height(), 1, 100); 489 | 490 | mpRenderSystem->mLight.position = 491 | Vec4d(mSpinLightX->value(), mSpinLightY->value(), mSpinLightZ->value(), 1); 492 | 493 | renderObj(); 494 | } 495 | 496 | void MainWindow::about() 497 | { 498 | QMessageBox::about(this, tr("About CG Z-Buffer"), 499 | tr("

A Z-Buffer project writed by maxint, in Janary, 2010.

" 500 | "

Email: lnychina@gmail.com

" 501 | "

Blog: http://hi.baidu.com/maxint

")); 502 | } 503 | 504 | void MainWindow::rotateBy(double xAngle, double yAngle, double zAngle) 505 | { 506 | static Mat22d matRot; 507 | static Vec3d eyePos; 508 | 509 | xRot += xAngle; 510 | yRot += yAngle; 511 | zRot += zAngle; 512 | xRot %= 360; 513 | yRot %= 360; 514 | zRot %= 360; 515 | 516 | eyePos[0] = mSpinEyeX->value(); 517 | eyePos[1] = mSpinEyeY->value(); 518 | eyePos[2] = mSpinEyeZ->value(); 519 | double len = eyePos.length(); 520 | eyePos[0] = 0; 521 | eyePos[1] = 0; 522 | eyePos[2] = len; 523 | 524 | matRot.rotate(-zRot); 525 | matRot.map(eyePos[0], eyePos[1], &eyePos[0], &eyePos[1]); 526 | matRot.rotate(yRot); 527 | matRot.map(eyePos[0], eyePos[2], &eyePos[0], &eyePos[2]); 528 | matRot.rotate(-xRot); 529 | matRot.map(eyePos[1], eyePos[2], &eyePos[1], &eyePos[2]); 530 | 531 | mSpinEyeX->setValue(eyePos[0]); 532 | mSpinEyeY->setValue(eyePos[1]); 533 | mSpinEyeZ->setValue(eyePos[2]); 534 | 535 | newFrustumOrLight(); 536 | } 537 | 538 | bool MainWindow::eventFilter(QObject *obj, QEvent *e) 539 | { 540 | if (obj->isWidgetType() && 541 | obj->objectName() == WIDGET_NAME) 542 | { 543 | QWidget *wid = static_cast(obj); 544 | if (e->type() == QEvent::Paint) 545 | { 546 | QPainter painter(wid); 547 | painter.drawImage(QPoint(0,0), mImage); 548 | e->accept(); 549 | return true; 550 | } 551 | //else if (mMouseOpAct->isChecked() && e->type() == QEvent::MouseMove) 552 | //{ 553 | // QMouseEvent *mouseE = static_cast(e); 554 | 555 | // double dx = mouseE->x() - lastPos.x(); 556 | // double dy = mouseE->y() - lastPos.y(); 557 | // dx = std::sqrt(dx); 558 | // dy = std::sqrt(dy); 559 | 560 | // if (mouseE->buttons() & Qt::LeftButton) { 561 | // rotateBy(dy, dx, 0); 562 | // } else if (mouseE->buttons() & Qt::RightButton) { 563 | // rotateBy(dy, 0, dx); 564 | // } 565 | // lastPos = mouseE->pos(); 566 | // mouseE->accept(); 567 | // return true; 568 | //} 569 | //else if (mMouseOpAct->isChecked() && e->type() == QEvent::MouseButtonPress) 570 | //{ 571 | // QMouseEvent *mouseE = static_cast(e); 572 | // lastPos = mouseE->pos(); 573 | // mouseE->accept(); 574 | // return true; 575 | //} 576 | } 577 | 578 | return QMainWindow::eventFilter(obj, e); 579 | } 580 | 581 | QString MainWindow::strippedName(const QString& fullFileName) 582 | { 583 | return QFileInfo(fullFileName).fileName(); 584 | } 585 | 586 | void MainWindow::drawCubeTest() 587 | { 588 | // cube /////////////////////////////////////////////////////////////////////// 589 | // v6----- v5 590 | // /| /| 591 | // v1------v0| 592 | // | | | | 593 | // | |v7---|-|v4 594 | // |/ |/ 595 | // v2------v3 596 | 597 | mpRenderSystem->begin(SL_QUADS); 598 | // face v0-v1-v2-v3 599 | mpRenderSystem->normal3d(0,0,1); 600 | mpRenderSystem->color3f(1,1,1); 601 | mpRenderSystem->vertex3d(1,1,1); 602 | mpRenderSystem->color3f(1,1,0); 603 | mpRenderSystem->vertex3d(-1,1,1); 604 | mpRenderSystem->color3f(1,0,0); 605 | mpRenderSystem->vertex3d(-1,-1,1); 606 | mpRenderSystem->color3f(1,0,1); 607 | mpRenderSystem->vertex3d(1,-1,1); 608 | 609 | // face v0-v3-v4-v6 610 | mpRenderSystem->normal3d(1,0,0); 611 | mpRenderSystem->color3f(1,1,1); 612 | mpRenderSystem->vertex3d(1,1,1); 613 | mpRenderSystem->color3f(1,0,1); 614 | mpRenderSystem->vertex3d(1,-1,1); 615 | mpRenderSystem->color3f(0,0,1); 616 | mpRenderSystem->vertex3d(1,-1,-1); 617 | mpRenderSystem->color3f(0,1,1); 618 | mpRenderSystem->vertex3d(1,1,-1); 619 | 620 | // face v0-v5-v6-v1 621 | mpRenderSystem->normal3d(0,1,0); 622 | mpRenderSystem->color3f(1,1,1); 623 | mpRenderSystem->vertex3d(1,1,1); 624 | mpRenderSystem->color3f(0,1,1); 625 | mpRenderSystem->vertex3d(1,1,-1); 626 | mpRenderSystem->color3f(0,1,0); 627 | mpRenderSystem->vertex3d(-1,1,-1); 628 | mpRenderSystem->color3f(1,1,0); 629 | mpRenderSystem->vertex3d(-1,1,1); 630 | 631 | // face v1-v6-v7-v2 632 | mpRenderSystem->normal3d(-1,0,0); 633 | mpRenderSystem->color3f(1,1,0); 634 | mpRenderSystem->vertex3d(-1,1,1); 635 | mpRenderSystem->color3f(0,1,0); 636 | mpRenderSystem->vertex3d(-1,1,-1); 637 | mpRenderSystem->color3f(0,0,0); 638 | mpRenderSystem->vertex3d(-1,-1,-1); 639 | mpRenderSystem->color3f(1,0,0); 640 | mpRenderSystem->vertex3d(-1,-1,1); 641 | 642 | // face v7-v4-v3-v2 643 | mpRenderSystem->normal3d(0,-1,0); 644 | mpRenderSystem->color3f(0,0,0); 645 | mpRenderSystem->vertex3d(-1,-1,-1); 646 | mpRenderSystem->color3f(0,0,1); 647 | mpRenderSystem->vertex3d(1,-1,-1); 648 | mpRenderSystem->color3f(1,0,1); 649 | mpRenderSystem->vertex3d(1,-1,1); 650 | mpRenderSystem->color3f(1,0,0); 651 | mpRenderSystem->vertex3d(-1,-1,1); 652 | 653 | // face v4-v7-v6-v5 654 | mpRenderSystem->normal3d(0,0,-1); 655 | mpRenderSystem->color3f(0,0,1); 656 | mpRenderSystem->vertex3d(1,-1,-1); 657 | mpRenderSystem->color3f(0,0,0); 658 | mpRenderSystem->vertex3d(-1,-1,-1); 659 | mpRenderSystem->color3f(0,1,0); 660 | mpRenderSystem->vertex3d(-1,1,-1); 661 | mpRenderSystem->color3f(0,1,1); 662 | mpRenderSystem->vertex3d(1,1,-1); 663 | mpRenderSystem->end(); 664 | } -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | class QMenu; 7 | class QAction; 8 | class QActionGroup; 9 | class CAccessObj; 10 | class CScanLine; 11 | class QDoubleSpinBox; 12 | 13 | class MainWindow : public QMainWindow 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | MainWindow(); 19 | MainWindow(const QString &fileName); 20 | ~MainWindow(); 21 | 22 | protected: 23 | bool eventFilter(QObject *obj, QEvent *e); 24 | QSize sizeHint() const; 25 | 26 | private: 27 | void setupUi(); 28 | void createActions(); 29 | void createMenus(); 30 | void createToolBars(); 31 | void createStatusBar(); 32 | void init(); 33 | void initRenderSystem(); 34 | void drawCubeTest(); 35 | void openObjFile(const QString& fileName); 36 | void renderObj(); 37 | void saveAsImageFile(const QString& fileName); 38 | void setResolution(int width, int height); 39 | QString strippedName(const QString& fullFileName); 40 | void rotateBy(double xAngle, double yAngle, double zAngle); 41 | 42 | private slots: 43 | void open(); 44 | void saveAs(); 45 | void resolution(); 46 | void shadeModel(QAction* act); 47 | void toggleView(QAction* act); 48 | void newFrustumOrLight(); 49 | void about(); 50 | 51 | private: 52 | QWidget *mImgView; 53 | QImage mImage; 54 | QMenu *mFileMenu; 55 | QMenu *mViewMenu; 56 | QMenu *mEditMenu; 57 | QMenu *mHelpMenu; 58 | QToolBar *mFileToolBar; 59 | QToolBar *mEditToolBar; 60 | QToolBar *mCameraLightToolBar; 61 | QAction *mOpenAct; 62 | QAction *mQuitAct; 63 | QAction *mSaveAsImageAct; 64 | QAction *mResolutionAct; 65 | QActionGroup *mShadeActGroup; 66 | QAction *mShadeFlatAct; 67 | QAction *mShadeSmoothAct; 68 | QAction *mToggleLightingAct; 69 | QAction *mRandomColorAct; 70 | QAction *mPointLightAct; 71 | QAction *mDirLightAct; 72 | QActionGroup *mViewActGroup; 73 | QAction *mViewToolBarAct; 74 | QAction *mAboutAct; 75 | QAction *mAboutQtAct; 76 | QAction *mMouseOpAct; 77 | 78 | QDoubleSpinBox *mSpinEyeX; 79 | QDoubleSpinBox *mSpinEyeY; 80 | QDoubleSpinBox *mSpinEyeZ; 81 | QDoubleSpinBox *mSpinLightX; 82 | QDoubleSpinBox *mSpinLightY; 83 | QDoubleSpinBox *mSpinLightZ; 84 | 85 | CAccessObj *mpAccessObj; 86 | CScanLine *mpRenderSystem; 87 | 88 | // mouse operations 89 | QPoint lastPos; 90 | int xRot; 91 | int yRot; 92 | int zRot; 93 | }; 94 | 95 | #endif // MAINWINDOW_H 96 | -------------------------------------------------------------------------------- /sdi.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/copy.png 4 | images/cut.png 5 | images/new.png 6 | images/open.png 7 | images/paste.png 8 | images/save.png 9 | 10 | 11 | -------------------------------------------------------------------------------- /zbuffer_qt.pri: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- 2 | # This file is generated by the Qt Visual Studio Add-in. 3 | # ------------------------------------------------------ 4 | 5 | HEADERS += ./AccessObj.h \ 6 | ./BasicStructure.h \ 7 | ./Camera.h \ 8 | ./mainwindow.h \ 9 | ./Mat.h \ 10 | ./MathDefs.h \ 11 | ./Point3D.h \ 12 | ./RenderState.h \ 13 | ./ScanLine.h \ 14 | ./Vec.h \ 15 | ./VectOps.h 16 | SOURCES += ./AccessObj.cpp \ 17 | ./Camera.cpp \ 18 | ./main.cpp \ 19 | ./mainwindow.cpp \ 20 | ./Point3D.cpp \ 21 | ./RenderState.cpp \ 22 | ./ScanLine.cpp \ 23 | ./VectOps.cpp 24 | RESOURCES += sdi.qrc 25 | -------------------------------------------------------------------------------- /zbuffer_qt.pro: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- 2 | # This file is generated by the Qt Visual Studio Add-in. 3 | # ------------------------------------------------------ 4 | 5 | TEMPLATE = app 6 | TARGET = zbuffer_qt 7 | DEFINES += _WINDOWS QT_LARGEFILE_SUPPORT QT_DLL 8 | INCLUDEPATH += . \ 9 | $(QTDIR)/mkspecs/win32-msvc2008 10 | DEPENDPATH += . 11 | UI_DIR += ./GeneratedFiles 12 | include(zbuffer_qt.pri) -------------------------------------------------------------------------------- /zbuffer_qt.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 26 | 29 | 32 | 35 | 38 | 44 | 63 | 66 | 70 | 73 | 86 | 89 | 92 | 95 | 98 | 101 | 104 | 107 | 108 | 116 | 119 | 122 | 125 | 128 | 134 | 153 | 156 | 160 | 163 | 177 | 180 | 183 | 186 | 189 | 192 | 195 | 198 | 199 | 200 | 201 | 202 | 203 | 208 | 211 | 212 | 215 | 216 | 219 | 220 | 223 | 224 | 227 | 228 | 231 | 232 | 235 | 236 | 239 | 240 | 241 | 246 | 249 | 252 | 259 | 260 | 263 | 270 | 271 | 272 | 275 | 278 | 285 | 286 | 289 | 296 | 297 | 298 | 301 | 304 | 311 | 312 | 315 | 322 | 323 | 324 | 327 | 330 | 337 | 338 | 341 | 348 | 349 | 350 | 353 | 356 | 363 | 364 | 367 | 374 | 375 | 376 | 379 | 382 | 389 | 390 | 393 | 400 | 401 | 402 | 405 | 408 | 415 | 416 | 419 | 426 | 427 | 428 | 431 | 434 | 441 | 442 | 445 | 452 | 453 | 454 | 457 | 460 | 467 | 468 | 471 | 478 | 479 | 480 | 483 | 486 | 493 | 494 | 497 | 504 | 505 | 506 | 509 | 512 | 519 | 520 | 523 | 530 | 531 | 532 | 533 | 538 | 541 | 545 | 548 | 549 | 550 | 555 | 558 | 561 | 564 | 565 | 569 | 572 | 573 | 574 | 575 | 580 | 583 | 587 | 590 | 591 | 594 | 597 | 598 | 599 | 600 | 601 | 607 | 610 | 613 | 620 | 621 | 624 | 631 | 632 | 633 | 636 | 639 | 646 | 647 | 650 | 657 | 658 | 659 | 662 | 665 | 672 | 673 | 676 | 683 | 684 | 685 | 688 | 691 | 698 | 699 | 702 | 709 | 710 | 711 | 714 | 717 | 724 | 725 | 728 | 735 | 736 | 737 | 740 | 743 | 750 | 751 | 754 | 761 | 762 | 763 | 766 | 769 | 776 | 777 | 780 | 787 | 788 | 789 | 790 | 791 | 792 | 796 | 797 | 798 | --------------------------------------------------------------------------------