frustum.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:6k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* Frustum
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include "engine.h"
  20. #include "bsp.h"
  21. #include "frustum.h"
  22. Frustum::Frustum() : num_planes(6), depth(0) {
  23. planes = new vec4[6 + DEPTH * 5];
  24. }
  25. Frustum::~Frustum() {
  26. delete planes;
  27. }
  28. /*
  29.  */
  30. void Frustum::get() {
  31. set(Engine::projection * Engine::modelview);
  32. }
  33. void Frustum::set(const mat4 &m) {
  34. #define PLANE(n,c0,c1,c2,c3) { 
  35. planes[n] = vec4(c0,c1,c2,c3); 
  36. planes[n] *= 1.0f / vec3(planes[n]).length(); 
  37. }
  38. PLANE(0,m[3]-m[0],m[7]-m[4],m[11]-m[8],m[15]-m[12])
  39. PLANE(1,m[3]+m[0],m[7]+m[4],m[11]+m[8],m[15]+m[12])
  40. PLANE(2,m[3]-m[1],m[7]-m[5],m[11]-m[9],m[15]-m[13])
  41. PLANE(3,m[3]+m[1],m[7]+m[5],m[11]+m[9],m[15]+m[13])
  42. PLANE(4,m[3]-m[2],m[7]-m[6],m[11]-m[10],m[15]-m[14])
  43. PLANE(5,m[3]+m[2],m[7]+m[6],m[11]+m[10],m[15]+m[14])
  44. #undef PLANE
  45. num_planes = 6;
  46. }
  47. /*
  48.  */
  49. void Frustum::addPortal(const vec3 &point,const vec3 *points) {
  50. depth++;
  51. if(depth > DEPTH) {
  52. fprintf(stderr,"Frustum::addPortal(): stack overflown");
  53. return;
  54. }
  55. #define PLANE(n,v0,v1,v2) { 
  56. vec3 normal; 
  57. normal.cross(v1 - v0,v2 - v0); 
  58. normal.normalize(); 
  59. planes[n] = vec4(normal,-normal * v0); 
  60. }
  61. if((Engine::camera - points[0]) * cross(points[1] - points[0],points[2] - points[0]) < 0.0) {
  62. PLANE(num_planes + 0,point,points[0],points[1]);
  63. PLANE(num_planes + 1,point,points[1],points[2]);
  64. PLANE(num_planes + 2,point,points[2],points[3]);
  65. PLANE(num_planes + 3,point,points[3],points[0]);
  66. PLANE(num_planes + 4,points[0],points[1],points[2]);
  67. } else {
  68. PLANE(num_planes + 0,point,points[0],points[3]);
  69. PLANE(num_planes + 1,point,points[3],points[2]);
  70. PLANE(num_planes + 2,point,points[2],points[1]);
  71. PLANE(num_planes + 3,point,points[1],points[0]);
  72. PLANE(num_planes + 4,points[2],points[1],points[0]);
  73. }
  74. #undef PLANE
  75. num_planes += 5;
  76. }
  77. void Frustum::removePortal() {
  78. if(depth > 0) {
  79. depth--;
  80. num_planes -= 5;
  81. }
  82. }
  83. /*****************************************************************************/
  84. /*                                                                           */
  85. /* inside                                                                    */
  86. /*                                                                           */
  87. /*****************************************************************************/
  88. /*
  89.  */
  90. int Frustum::inside(const vec3 &min,const vec3 &max) {
  91. for(int i = 0; i < num_planes; i++) {
  92. if(planes[i] * vec4(min[0],min[1],min[2],1) > 0) continue;
  93. if(planes[i] * vec4(min[0],min[1],max[2],1) > 0) continue;
  94. if(planes[i] * vec4(min[0],max[1],min[2],1) > 0) continue;
  95. if(planes[i] * vec4(min[0],max[1],max[2],1) > 0) continue;
  96. if(planes[i] * vec4(max[0],min[1],min[2],1) > 0) continue;
  97. if(planes[i] * vec4(max[0],min[1],max[2],1) > 0) continue;
  98. if(planes[i] * vec4(max[0],max[1],min[2],1) > 0) continue;
  99. if(planes[i] * vec4(max[0],max[1],max[2],1) > 0) continue;
  100. return 0;
  101. }
  102. return 1;
  103. }
  104. int Frustum::inside(const vec3 &center,float radius) {
  105. for(int i = 0; i < num_planes; i++) {
  106. if(planes[i] * vec4(center,1) < -radius) return 0;
  107. }
  108. return 1;
  109. }
  110. int Frustum::inside(const vec3 *points,int num) {
  111. for(int i = 0; i < num_planes; i++) {
  112. int j = 0;
  113. for(; j < num; j++) if(planes[i] * vec4(points[j],1) > 0) break;
  114. if(j == num) return 0;
  115. }
  116. return 1;
  117. }
  118. int Frustum::inside(const vec3 &light,float light_radius,const vec3 &center,float radius) {
  119. vec3 dir = center - light;
  120. float length = dir.length();
  121. if(length < radius) return 1;
  122. if(length > radius + light_radius) return 0;
  123. vec3 x,y,c,points[8];
  124. dir.normalize();
  125. if(fabs(dir.z) > 1.0 - EPSILON) {
  126. x.cross(dir,vec3(1,0,0));
  127. x.normalize();
  128. y.cross(dir,x);
  129. y.normalize();
  130. } else {
  131. x.cross(dir,vec3(0,0,1));
  132. x.normalize();
  133. y.cross(dir,x);
  134. y.normalize();
  135. }
  136. float size = radius * (length - radius) / length;
  137. x *= size;
  138. y *= size;
  139. c = light + dir * (length - radius);
  140. points[0] = x + y + c;
  141. points[1] = x - y + c;
  142. points[2] = -x + y + c;
  143. points[3] = -x - y + c;
  144. size = light_radius / (length - radius);
  145. x *= size;
  146. y *= size;
  147. c = light + dir * light_radius;
  148. points[4] = x + y + c;
  149. points[5] = x - y + c;
  150. points[6] = -x + y + c;
  151. points[7] = -x - y + c;
  152. return inside(points,8);
  153. }
  154. /*
  155.  */
  156. int Frustum::inside_all(const vec3 &min,const vec3 &max) {
  157. for(int i = 0; i < num_planes; i++) {
  158. if(planes[i] * vec4(min[0],min[1],min[2],1) < 0) return 0;
  159. if(planes[i] * vec4(min[0],min[1],max[2],1) < 0) return 0;
  160. if(planes[i] * vec4(min[0],max[1],min[2],1) < 0) return 0;
  161. if(planes[i] * vec4(min[0],max[1],max[2],1) < 0) return 0;
  162. if(planes[i] * vec4(max[0],min[1],min[2],1) < 0) return 0;
  163. if(planes[i] * vec4(max[0],min[1],max[2],1) < 0) return 0;
  164. if(planes[i] * vec4(max[0],max[1],min[2],1) < 0) return 0;
  165. if(planes[i] * vec4(max[0],max[1],max[2],1) < 0) return 0;
  166. }
  167. return 1;
  168. }
  169. int Frustum::inside_all(const vec3 &center,float radius) {
  170. for(int i = 0; i < num_planes; i++) {
  171. if(planes[i] * vec4(center,1) < radius) return 0;
  172. }
  173. return 1;
  174. }