00001 #include "GraphicalObject.h"
00002 #include "Utility.h"
00003
00004
00005 GraphicalObject::GraphicalObject (RawObject * raw_obj)
00006 {
00007
00008
00009 first_child = NULL;
00010 raw_object = raw_obj;
00011 position = new PositionPath ();
00012
00013
00014 position->SetConstantPosition (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
00015
00016
00017 if (raw_object != NULL)
00018 {bounding_radius = raw_object->GetBoundingRadius ();}
00019 else
00020 {bounding_radius = 0.0;}
00021
00022
00023 if (raw_object != NULL)
00024 {bounding_box = raw_object->GetBoundingBox ();}
00025 else
00026 {
00027 bounding_box.xmax = 0.0f;
00028 bounding_box.xmin = 0.0f;
00029 bounding_box.ymax = 0.0f;
00030 bounding_box.ymin = 0.0f;
00031 bounding_box.zmax = 0.0f;
00032 bounding_box.zmin = 0.0f;
00033 }
00034
00035
00036 UpdateBoxCorners ();
00037 last_outside = 0;
00038 }
00039
00040 GraphicalObject::~GraphicalObject ()
00041 {
00042
00043 }
00044
00045 void GraphicalObject::ApplyTransformation (const Position & position, bool rotation)
00046 {
00047
00048
00049 glTranslatef (position.x, position.y, position.z);
00050 if (rotation)
00051 {
00052 glRotatef (position.yaw, 0.0f, 0.0f, 1.0f);
00053 glRotatef (position.pitch, 0.0f, 1.0f, 0.0f);
00054 glRotatef (position.roll, 1.0f, 0.0f, 0.0f);
00055 }
00056 }
00057
00058 void GraphicalObject::UndoTransformation (const Position & position, bool rotation)
00059 {
00060
00061 if (rotation)
00062 {
00063 glRotatef (-position.roll, 1.0f, 0.0f, 0.0f);
00064 glRotatef (-position.pitch, 0.0f, 1.0f, 0.0f);
00065 glRotatef (-position.yaw, 0.0f, 0.0f, 1.0f);
00066 }
00067 glTranslatef (-position.x, -position.y, -position.z);
00068 }
00069
00070 void GraphicalObject::UpdateBoundingRadius (bool recurse)
00071 {
00072 ChildListElem * current_child;
00073 BoundingBox child_translation;
00074 Point corner;
00075 double temp;
00076 double max;
00077 int index;
00078
00079
00080 if (recurse)
00081 {
00082 current_child = first_child;
00083 while (current_child != NULL)
00084 {
00085 current_child->object->UpdateBoundingRadius (recurse);
00086 current_child = current_child->next;
00087 }
00088 }
00089
00090
00091 ComputeBoundingRadius ();
00092
00093
00094 current_child = first_child;
00095 max = 0.0;
00096
00097 while (current_child != NULL)
00098 {
00099 child_translation = current_child->object->position->GetTranslationBox ();
00100
00101
00102 for (index = 0; index < 8; index++)
00103 {
00104 corner = Utility::GetPointFromBox (child_translation, index);
00105 temp = sqrt (corner.x * corner.x + corner.y * corner.y + corner.z * corner.z);
00106 temp += current_child->object->bounding_radius;
00107 if (temp > max) max = temp;
00108 }
00109
00110 current_child = current_child ->next;
00111 }
00112
00113
00114 if (max > bounding_radius) bounding_radius = max;
00115 }
00116
00117 void GraphicalObject::UpdateBoundingBox (bool recurse)
00118 {
00119 ChildListElem * current_child;
00120 BoundingBox child_box;
00121 BoundingBox child_translation;
00122 Position child_position;
00123
00124
00125 if (recurse)
00126 {
00127 current_child = first_child;
00128 while (current_child != NULL)
00129 {
00130 current_child->object->UpdateBoundingBox (recurse);
00131 current_child = current_child->next;
00132 }
00133 }
00134
00135
00136 ComputeBoundingBox ();
00137
00138
00139 current_child = first_child;
00140 while (current_child != NULL)
00141 {
00142
00143 child_translation = current_child->object->position->GetTranslationBox ();
00144 child_box = current_child->object->bounding_box;
00145
00146 if (current_child->object->position->HasDynamicRotation ())
00147 {
00148
00149 double max_dist;
00150 double x_max, y_max, z_max;
00151
00152
00153 abs (child_box.xmax) > abs (child_box.xmin) ? x_max = abs (child_box.xmax): x_max = abs (child_box.xmin);
00154 abs (child_box.ymax) > abs (child_box.ymin) ? y_max = abs (child_box.ymax): y_max = abs (child_box.ymin);
00155 abs (child_box.zmax) > abs (child_box.zmin) ? z_max = abs (child_box.zmax): z_max = abs (child_box.zmin);
00156 max_dist = sqrt (x_max * x_max + y_max * y_max + z_max * z_max);
00157
00158
00159 if (bounding_box.xmax < child_translation.xmax + max_dist) bounding_box.xmax = child_translation.xmax + max_dist;
00160 if (bounding_box.xmin > child_translation.xmin - max_dist) bounding_box.xmin = child_translation.xmin - max_dist;
00161 if (bounding_box.ymax < child_translation.ymax + max_dist) bounding_box.ymax = child_translation.ymax + max_dist;
00162 if (bounding_box.ymin > child_translation.ymin - max_dist) bounding_box.ymin = child_translation.ymin - max_dist;
00163 if (bounding_box.zmax < child_translation.zmax + max_dist) bounding_box.zmax = child_translation.zmax + max_dist;
00164 if (bounding_box.zmin > child_translation.zmin - max_dist) bounding_box.zmin = child_translation.zmin - max_dist;
00165
00166 }
00167 else
00168 {
00169
00170
00171
00172 float matrix[16];
00173 Point corner;
00174 Point result;
00175
00176
00177 child_position = current_child->object->position->GetPosition (0);
00178 child_position.x = 0.0f;
00179 child_position.y = 0.0f;
00180 child_position.z = 0.0f;
00181
00182
00183 glPushMatrix ();
00184 glLoadIdentity ();
00185
00186 current_child->object->ApplyTransformation (child_position, true);
00187 glGetFloatv (GL_MODELVIEW_MATRIX, matrix);
00188
00189 glPopMatrix ();
00190
00191
00192 for (int index = 0; index < 8; index++)
00193 {
00194 corner = Utility::GetPointFromBox (child_box, index);
00195 Geometry::VectorMultiply (matrix, corner, result);
00196
00197 if (result.x + child_translation.xmax > bounding_box.xmax) bounding_box.xmax = result.x + child_translation.xmax;
00198 if (result.x + child_translation.xmin < bounding_box.xmin) bounding_box.xmin = result.x + child_translation.xmin;
00199 if (result.y + child_translation.ymax > bounding_box.ymax) bounding_box.ymax = result.y + child_translation.ymax;
00200 if (result.y + child_translation.ymin < bounding_box.ymin) bounding_box.ymin = result.y + child_translation.ymin;
00201 if (result.z + child_translation.zmax > bounding_box.zmax) bounding_box.zmax = result.z + child_translation.zmax;
00202 if (result.z + child_translation.zmin < bounding_box.zmin) bounding_box.zmin = result.z + child_translation.zmin;
00203 }
00204 }
00205
00206 current_child = current_child->next;
00207 }
00208
00209 UpdateBoxCorners ();
00210 }
00211
00212 void GraphicalObject::DrawBoundingSphere (int culling_result)
00213 {
00214 if (culling_result == C_OUTSIDE)
00215 {glColor3f (1.0f, 0.2f, 0.2f);}
00216 if (culling_result == C_PARTIAL)
00217 {glColor3f (1.0f, 0.7f, 0.4f);}
00218 if (culling_result == C_INSIDE)
00219 {glColor3f (0.0f, 1.0f, 0.2f);}
00220
00221 glutWireSphere (bounding_radius, 8, 8);
00222 }
00223
00224 void GraphicalObject::DrawBoundingBox (int culling_result)
00225 {
00226 if (culling_result == C_OUTSIDE)
00227 {Utility::SetColor (1.0f, 0.2f, 0.2f, 1.0f);}
00228 if (culling_result == C_PARTIAL)
00229 {Utility::SetColor (1.0f, 0.7f, 0.4f, 1.0f);}
00230 if (culling_result == C_INSIDE)
00231 {Utility::SetColor (0.0f, 1.0f, 0.2f, 1.0f);}
00232
00233 Utility::DrawBoundingBox (bounding_box);
00234 }
00235
00236 int GraphicalObject::CullObject (Camera * camera, Camera * monitor, int culling_mode, bool show)
00237 {
00238 int result;
00239
00240 glDisable (GL_LIGHTING);
00241
00242 switch (culling_mode)
00243 {
00244 case C_SPHERE: if (monitor == NULL)
00245 {result = SphereCulling2 (camera);}
00246 else
00247 {result = SphereCulling (camera, monitor);}
00248 if (show)
00249 {DrawBoundingSphere (result);}
00250 break;
00251 case C_BOUNDING_BOX: if (monitor == NULL)
00252 {result = BoxCulling2 (camera);}
00253 else
00254 {result = BoxCulling (camera, monitor);}
00255 if (show)
00256 {DrawBoundingBox (result);}
00257 break;
00258 case C_MIXED: if (monitor == NULL)
00259 {
00260 result = SphereCulling2 (camera);
00261 if (show)
00262 {DrawBoundingSphere (result);}
00263 if (result == C_PARTIAL)
00264 {
00265 result = BoxCulling2 (camera);
00266 if (show)
00267 {DrawBoundingBox (result);}
00268 }
00269 }
00270 else
00271 {
00272 result = SphereCulling (camera, monitor);
00273 if (show)
00274 {DrawBoundingSphere (result);}
00275 if (result == C_PARTIAL)
00276 {
00277 result = BoxCulling (camera, monitor);
00278 if (show)
00279 {DrawBoundingBox (result);}
00280 }
00281 }
00282 break;
00283 case C_NONE: result = C_INSIDE;
00284 break;
00285 default: break;
00286 }
00287
00288 glEnable (GL_LIGHTING);
00289
00290 return result;
00291 }
00292
00293 void GraphicalObject::UpdateBoxCorners ()
00294 {
00295 for (int index = 0; index < 8; index++)
00296 {
00297 box_corners.p[index] = Utility::GetPointFromBox (bounding_box, index);
00298 }
00299 last_outside = 0;
00300 }
00301
00302
00303 void GraphicalObject::CalculateRelativePositions ()
00304 {
00305 ChildListElem * current_object;
00306 Position child_pos;
00307 Point average = {0.0f, 0.0f, 0.0f};
00308 int num_children = 0;
00309
00310
00311 current_object = first_child;
00312 while (current_object != NULL)
00313 {
00314 num_children++;
00315 current_object->object->CalculateRelativePositions ();
00316 current_object = current_object->next;
00317 }
00318
00319
00320 ComputeBoundingRadius ();
00321 ComputeBoundingBox ();
00322
00323 if (num_children == 0) return;
00324
00325
00326 current_object = first_child;
00327 while (current_object != NULL)
00328 {
00329 child_pos = current_object->object->position->GetPosition (0);
00330 average.x += child_pos.x;
00331 average.y += child_pos.y;
00332 average.z += child_pos.z;
00333 current_object = current_object->next;
00334 }
00335 average.x /= num_children;
00336 average.y /= num_children;
00337 average.z /= num_children;
00338
00339
00340 current_object = first_child;
00341 while (current_object != NULL)
00342 {
00343 current_object->object->position->Shift (-average.x, -average.y, -average.z);
00344 current_object = current_object->next;
00345 }
00346 position->Shift (average.x, average.y, average.z);
00347
00348 UpdateBoundingRadius (true);
00349 UpdateBoundingBox (true);
00350 }
00351
00352 int GraphicalObject::SphereCulling (Camera * camera, Camera * monitor)
00353 {
00354 Point pos;
00355 Point origin;
00356 float temp_left, temp_right, temp_front, temp_back, temp_bottom, temp_top;
00357 float mod[16];
00358 float * inv_view;
00359
00360 glGetFloatv (GL_MODELVIEW_MATRIX, mod);
00361 inv_view = monitor->GetInverseView ();
00362
00363
00364
00365 origin.x = mod[12];
00366 origin.y = mod[13];
00367 origin.z = mod[14];
00368
00369 pos.x = origin.x * inv_view[0] + origin.y * inv_view[4] + origin.z * inv_view[8] + inv_view[12];
00370 pos.y = origin.x * inv_view[1] + origin.y * inv_view[5] + origin.z * inv_view[9] + inv_view[13];
00371 pos.z = origin.x * inv_view[2] + origin.y * inv_view[6] + origin.z * inv_view[10] + inv_view[14];
00372
00373
00374 temp_left = camera->left.n.x * pos.x + camera->left.n.y * pos.y + camera->left.n.z * pos.z + camera->left.d;
00375 if (temp_left < - bounding_radius)
00376 {return C_OUTSIDE;}
00377
00378
00379 temp_right = camera->right.n.x * pos.x + camera->right.n.y * pos.y + camera->right.n.z * pos.z + camera->right.d;
00380 if (temp_right < - bounding_radius)
00381 {return C_OUTSIDE;}
00382
00383
00384 temp_top = camera->top.n.x * pos.x + camera->top.n.y * pos.y + camera->top.n.z * pos.z + camera->top.d;
00385 if (temp_top < - bounding_radius)
00386 {return C_OUTSIDE;}
00387
00388
00389 temp_bottom = camera->bottom.n.x * pos.x + camera->bottom.n.y * pos.y + camera->bottom.n.z * pos.z + camera->bottom.d;
00390 if (temp_bottom < - bounding_radius)
00391 {return C_OUTSIDE;}
00392
00393
00394 temp_front = camera->front.n.x * pos.x + camera->front.n.y * pos.y + camera->front.n.z * pos.z + camera->front.d;
00395 if (temp_front < - bounding_radius)
00396 {return C_OUTSIDE;}
00397
00398
00399 temp_back = camera->back.n.x * pos.x + camera->back.n.y * pos.y + camera->back.n.z * pos.z + camera->back.d;
00400 if (temp_back < - bounding_radius)
00401 {return C_OUTSIDE;}
00402
00403
00404 if (temp_left < bounding_radius || temp_right < bounding_radius || temp_top < bounding_radius ||
00405 temp_bottom < bounding_radius || temp_front < bounding_radius || temp_back < bounding_radius)
00406 {return C_PARTIAL;}
00407
00408 return C_INSIDE;
00409 }
00410
00411 int GraphicalObject::SphereCulling2 (Camera * camera)
00412 {
00413 float mod[16];
00414 float res[6];
00415 float x, y, z;
00416
00417 glGetFloatv (GL_MODELVIEW_MATRIX, mod);
00418
00419
00420
00421 x = mod[12];
00422 y = mod[13];
00423 z = mod[14];
00424
00425 for (int index = 0; index < 6; index++)
00426 {
00427 res[index] = x * camera->planes[index].n.x + y * camera->planes[index].n.y + z * camera->planes[index].n.z + camera->planes[index].d;
00428 if (res[index] < - bounding_radius) return C_OUTSIDE;
00429 }
00430
00431 if (res[0] < bounding_radius || res[1] < bounding_radius || res[2] < bounding_radius ||
00432 res[3] < bounding_radius || res[4] < bounding_radius || res[5] < bounding_radius )
00433 {
00434 return C_PARTIAL;
00435 }
00436
00437 return C_INSIDE;
00438
00439 }
00440
00441 int GraphicalObject::BoxCulling (Camera * camera, Camera * monitor)
00442 {
00443 int index;
00444 float mod[16];
00445 float * inv_view;
00446 Point temp_point[8];
00447 Point corner[8];
00448 bool inside;
00449 bool outside;
00450
00451
00452 glGetFloatv (GL_MODELVIEW_MATRIX, mod);
00453 inv_view = monitor->GetInverseView ();
00454
00455
00456 for (index = 0; index < 8; index++)
00457 {
00458 Geometry::VectorMultiply (mod, box_corners.p[index], temp_point[index]);
00459 Geometry::VectorMultiply (inv_view, temp_point[index], corner[index]);
00460 }
00461
00462
00463 inside = true;
00464 outside = true;
00465 for (index = 0; index < 8; index++)
00466 {
00467 if (corner[index].x * camera->left.n.x + corner[index].y * camera->left.n.y +
00468 corner[index].z * camera->left.n.z + camera->left.d >= 0)
00469 {outside = false;}
00470 else
00471 {inside = false;}
00472 }
00473 if (outside) return C_OUTSIDE;
00474
00475 outside = true;
00476 for (index = 0; index < 8; index++)
00477 {
00478 if (corner[index].x * camera->right.n.x + corner[index].y * camera->right.n.y +
00479 corner[index].z * camera->right.n.z + camera->right.d >= 0)
00480 {outside = false;}
00481 else
00482 {inside = false;}
00483 }
00484 if (outside) return C_OUTSIDE;
00485
00486 outside = true;
00487 for (index = 0; index < 8; index++)
00488 {
00489 if (corner[index].x * camera->top.n.x + corner[index].y * camera->top.n.y +
00490 corner[index].z * camera->top.n.z + camera->top.d >= 0)
00491 {outside = false;}
00492 else
00493 {inside = false;}
00494 }
00495 if (outside) return C_OUTSIDE;
00496
00497 outside = true;
00498 for (index = 0; index < 8; index++)
00499 {
00500 if (corner[index].x * camera->bottom.n.x + corner[index].y * camera->bottom.n.y +
00501 corner[index].z * camera->bottom.n.z + camera->bottom.d >= 0)
00502 {outside = false;}
00503 else
00504 {inside = false;}
00505 }
00506 if (outside) return C_OUTSIDE;
00507
00508 outside = true;
00509 for (index = 0; index < 8; index++)
00510 {
00511 if (corner[index].x * camera->front.n.x + corner[index].y * camera->front.n.y +
00512 corner[index].z * camera->front.n.z + camera->front.d >= 0)
00513 {outside = false;}
00514 else
00515 {inside = false;}
00516 }
00517 if (outside) return C_OUTSIDE;
00518
00519 outside = true;
00520 for (index = 0; index < 8; index++)
00521 {
00522 if (corner[index].x * camera->back.n.x + corner[index].y * camera->back.n.y +
00523 corner[index].z * camera->back.n.z + camera->back.d >= 0)
00524 {outside = false;}
00525 else
00526 {inside = false;}
00527 }
00528 if (outside) return C_OUTSIDE;
00529
00530 if (inside) return C_INSIDE;
00531
00532 return C_PARTIAL;
00533 }
00534
00535 int GraphicalObject::BoxCulling2 (Camera * camera)
00536 {
00537 int point_index, plane_index, counter;
00538 float mod[16];
00539 Point corner[8];
00540 bool inside;
00541 bool outside;
00542
00543
00544 glGetFloatv (GL_MODELVIEW_MATRIX, mod);
00545
00546
00547 for (point_index = 0; point_index < 8; point_index++)
00548 {Geometry::VectorMultiply (mod, box_corners.p[point_index], corner[point_index]);}
00549
00550
00551 inside = true;
00552 for (counter = 0, plane_index = last_outside; counter < 6; counter++, plane_index < 5 ? plane_index++ : plane_index = 0)
00553 {
00554 outside = true;
00555 for (point_index = 0; point_index < 8; point_index++)
00556 {
00557 if (corner[point_index].x * camera->planes[plane_index].n.x + corner[point_index].y * camera->planes[plane_index].n.y +
00558 corner[point_index].z * camera->planes[plane_index].n.z + camera->planes[plane_index].d >= 0)
00559 {outside = false;}
00560 else
00561 {inside = false;}
00562 }
00563 if (outside)
00564 {
00565 last_outside = plane_index;
00566 return C_OUTSIDE;
00567 }
00568 }
00569 if (inside) return C_INSIDE;
00570
00571 return C_PARTIAL;
00572 }