00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "fisheyeMaker.h"
00016 #include "geomNode.h"
00017 #include "geom.h"
00018 #include "geomTristrips.h"
00019 #include "geomVertexWriter.h"
00020 #include "geomVertexFormat.h"
00021 #include "geomVertexArrayFormat.h"
00022 #include "internalName.h"
00023 #include "luse.h"
00024 #include "cmath.h"
00025 #include "mathNumbers.h"
00026 #include "graphicsStateGuardian.h"
00027 #include "displayRegion.h"
00028
00029
00030
00031
00032
00033
00034 void FisheyeMaker::
00035 reset() {
00036 set_fov(360.0);
00037 _num_vertices = 1000;
00038 _square_inscribed = false;
00039 _square_radius = 1.0f;
00040 set_reflection(false);
00041 }
00042
00043
00044
00045
00046
00047
00048
00049
00050 void FisheyeMaker::
00051 set_fov(PN_stdfloat fov) {
00052 _fov = fov;
00053 _half_fov_rad = deg_2_rad(_fov * 0.5f);
00054 }
00055
00056
00057
00058
00059
00060
00061
00062
00063 PT(PandaNode) FisheyeMaker::
00064 generate() {
00065
00066 int max_vertices_per_array = 100;
00067 int max_vertices_per_primitive = 10000;
00068 bool prefers_triangle_strips = true;
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 PN_stdfloat vertices_per_unit = csqrt(_num_vertices / MathNumbers::pi_f);
00088 PN_stdfloat two_pi = 2.0f * MathNumbers::pi_f;
00089
00090
00091
00092 int num_rings = (int)floor(vertices_per_unit + 0.5f);
00093
00094 CPT(GeomVertexFormat) format = GeomVertexFormat::register_format
00095 (new GeomVertexArrayFormat
00096 (InternalName::get_vertex(), 3,
00097 Geom::NT_stdfloat, Geom::C_point,
00098 InternalName::get_texcoord(), 3,
00099 Geom::NT_stdfloat, Geom::C_texcoord));
00100
00101 PT(GeomVertexData) vdata =
00102 new GeomVertexData(get_name(), format, Geom::UH_static);
00103 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00104 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00105
00106 PT(Geom) geom = new Geom(vdata);
00107 PT(GeomPrimitive) tristrips = new GeomTristrips(Geom::UH_static);
00108 tristrips->set_shade_model(Geom::SM_uniform);
00109
00110 PT(GeomNode) geom_node = new GeomNode(get_name());
00111
00112 int last_ring_size = 3;
00113 int last_ring_vertex = 0;
00114 PN_stdfloat last_r = 1.0f / (PN_stdfloat)num_rings;
00115
00116
00117
00118
00119 for (int vi = 0; vi < last_ring_size; ++vi) {
00120 add_vertex(vertex, texcoord, last_r,
00121 two_pi * (PN_stdfloat)vi / (PN_stdfloat)last_ring_size);
00122 tristrips->add_vertex(vi);
00123 }
00124
00125
00126 tristrips->add_vertex(2);
00127 tristrips->close_primitive();
00128
00129
00130 for (int ri = 1; ri < num_rings; ++ri) {
00131 PN_stdfloat r = (PN_stdfloat)(ri + 1) / (PN_stdfloat)num_rings;
00132
00133
00134 PN_stdfloat c = two_pi * r;
00135 int ring_size = (int)floor(c * vertices_per_unit + 0.5f);
00136
00137
00138
00139 if (ring_size < last_ring_size * 2) {
00140
00141 ring_size = last_ring_size;
00142 } else {
00143
00144 ring_size = last_ring_size * 2;
00145 }
00146
00147 if (vdata->get_num_rows() + ring_size > max_vertices_per_array) {
00148
00149 if (tristrips->get_num_vertices() != 0) {
00150 geom->add_primitive(tristrips);
00151 }
00152 if (geom->get_num_primitives() != 0) {
00153 if (prefers_triangle_strips) {
00154 geom_node->add_geom(geom);
00155 } else {
00156 geom_node->add_geom(geom->decompose());
00157 }
00158 }
00159
00160 vdata = new GeomVertexData(get_name(), format, Geom::UH_static);
00161 vertex = GeomVertexWriter(vdata, InternalName::get_vertex());
00162 texcoord = GeomVertexWriter(vdata, InternalName::get_texcoord());
00163 geom = new Geom(vdata);
00164 tristrips = new GeomTristrips(Geom::UH_static);
00165 tristrips->set_shade_model(Geom::SM_uniform);
00166
00167
00168 last_ring_vertex = 0;
00169 for (int vi = 0; vi < last_ring_size; ++vi) {
00170 add_vertex(vertex, texcoord, last_r,
00171 two_pi * (PN_stdfloat)vi / (PN_stdfloat)last_ring_size);
00172 }
00173 }
00174
00175
00176 int ring_vertex = vdata->get_num_rows();
00177 for (int vi = 0; vi < ring_size; ++vi) {
00178 add_vertex(vertex, texcoord, r,
00179 two_pi * (PN_stdfloat)vi / (PN_stdfloat)ring_size);
00180 }
00181
00182
00183 if (ring_size == last_ring_size) {
00184
00185 if ((ring_size + 1) * 2 > max_vertices_per_primitive) {
00186
00187
00188 int piece_size = max_vertices_per_primitive / 2 - 1;
00189 int vi = 0;
00190 while (vi < ring_size) {
00191 int piece_end = min(ring_size + 1, piece_size + 1 + vi);
00192 for (int pi = vi; pi < piece_end; ++pi) {
00193 tristrips->add_vertex(last_ring_vertex + pi % last_ring_size);
00194 tristrips->add_vertex(ring_vertex + pi % ring_size);
00195 }
00196 tristrips->close_primitive();
00197 vi += piece_size;
00198 }
00199
00200 } else {
00201
00202 if (tristrips->get_num_vertices() > 0 &&
00203 tristrips->get_num_vertices() + ring_size * 2 > max_vertices_per_primitive) {
00204 geom->add_primitive(tristrips);
00205 tristrips = new GeomTristrips(Geom::UH_static);
00206 tristrips->set_shade_model(Geom::SM_uniform);
00207 }
00208 for (int vi = 0; vi < ring_size; ++vi) {
00209 tristrips->add_vertex(last_ring_vertex + vi);
00210 tristrips->add_vertex(ring_vertex + vi);
00211 }
00212 tristrips->add_vertex(last_ring_vertex);
00213 tristrips->add_vertex(ring_vertex);
00214 tristrips->close_primitive();
00215 }
00216
00217 } else {
00218
00219
00220
00221
00222 int vi = 0;
00223 while (vi < last_ring_size) {
00224 if (tristrips->get_num_vertices() + 10 > max_vertices_per_primitive) {
00225 geom->add_primitive(tristrips);
00226 tristrips = new GeomTristrips(Geom::UH_static);
00227 tristrips->set_shade_model(Geom::SM_uniform);
00228 }
00229 tristrips->add_vertex(ring_vertex + (vi * 2 + 1) % ring_size);
00230 tristrips->add_vertex(ring_vertex + (vi * 2 + 2) % ring_size);
00231 tristrips->add_vertex(last_ring_vertex + (vi + 1) % last_ring_size);
00232 tristrips->add_vertex(ring_vertex + (vi * 2 + 3) % ring_size);
00233 tristrips->add_vertex(last_ring_vertex + (vi + 2) % last_ring_size);
00234 tristrips->add_vertex(ring_vertex + (vi * 2 + 4) % ring_size);
00235 tristrips->close_primitive();
00236
00237 tristrips->add_vertex(ring_vertex + (vi * 2 + 4) % ring_size);
00238 tristrips->add_vertex(ring_vertex + (vi * 2 + 5) % ring_size);
00239 tristrips->add_vertex(last_ring_vertex + (vi + 2) % last_ring_size);
00240 tristrips->add_vertex(last_ring_vertex + (vi + 3) % last_ring_size);
00241 tristrips->close_primitive();
00242
00243 vi += 2;
00244 }
00245 }
00246
00247 last_ring_size = ring_size;
00248 last_ring_vertex = ring_vertex;
00249 last_r = r;
00250 }
00251
00252 if (_square_inscribed) {
00253
00254 int ring_size = last_ring_size;
00255
00256 if (vdata->get_num_rows() + ring_size > max_vertices_per_array) {
00257
00258 if (tristrips->get_num_vertices() != 0) {
00259 geom->add_primitive(tristrips);
00260 }
00261 if (geom->get_num_primitives() != 0) {
00262 if (prefers_triangle_strips) {
00263 geom_node->add_geom(geom);
00264 } else {
00265 geom_node->add_geom(geom->decompose());
00266 }
00267 }
00268
00269 vdata = new GeomVertexData(get_name(), format, Geom::UH_static);
00270 vertex = GeomVertexWriter(vdata, InternalName::get_vertex());
00271 texcoord = GeomVertexWriter(vdata, InternalName::get_texcoord());
00272 geom = new Geom(vdata);
00273 tristrips = new GeomTristrips(Geom::UH_static);
00274 tristrips->set_shade_model(Geom::SM_uniform);
00275
00276
00277 last_ring_vertex = 0;
00278 for (int vi = 0; vi < last_ring_size; ++vi) {
00279 add_vertex(vertex, texcoord, last_r,
00280 two_pi * (PN_stdfloat)vi / (PN_stdfloat)last_ring_size);
00281 }
00282 }
00283
00284
00285 int ring_vertex = vdata->get_num_rows();
00286 for (int vi = 0; vi < ring_size; ++vi) {
00287 add_square_vertex(vertex, texcoord,
00288 two_pi * (PN_stdfloat)vi / (PN_stdfloat)ring_size);
00289 }
00290
00291
00292 if ((ring_size + 1) * 2 > max_vertices_per_primitive) {
00293
00294
00295 int piece_size = max_vertices_per_primitive / 2 - 1;
00296 int vi = 0;
00297 while (vi < ring_size) {
00298 int piece_end = min(ring_size + 1, piece_size + 1 + vi);
00299 for (int pi = vi; pi < piece_end; ++pi) {
00300 tristrips->add_vertex(last_ring_vertex + pi % last_ring_size);
00301 tristrips->add_vertex(ring_vertex + pi % ring_size);
00302 }
00303 tristrips->close_primitive();
00304 vi += piece_size;
00305 }
00306
00307 } else {
00308
00309 if (tristrips->get_num_vertices() > 0 &&
00310 tristrips->get_num_vertices() + ring_size * 2 > max_vertices_per_primitive) {
00311 geom->add_primitive(tristrips);
00312 tristrips = new GeomTristrips(Geom::UH_static);
00313 tristrips->set_shade_model(Geom::SM_uniform);
00314 }
00315 for (int vi = 0; vi < ring_size; ++vi) {
00316 tristrips->add_vertex(last_ring_vertex + vi);
00317 tristrips->add_vertex(ring_vertex + vi);
00318 }
00319 tristrips->add_vertex(last_ring_vertex);
00320 tristrips->add_vertex(ring_vertex);
00321 tristrips->close_primitive();
00322 }
00323 }
00324
00325 if (tristrips->get_num_vertices() != 0) {
00326 geom->add_primitive(tristrips);
00327 }
00328 if (geom->get_num_primitives() != 0) {
00329 if (prefers_triangle_strips) {
00330 geom_node->add_geom(geom);
00331 } else {
00332 geom_node->add_geom(geom->decompose());
00333 }
00334 }
00335
00336 return geom_node.p();
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 void FisheyeMaker::
00348 add_vertex(GeomVertexWriter &vertex, GeomVertexWriter &texcoord,
00349 PN_stdfloat r, PN_stdfloat a) {
00350 PN_stdfloat sina, cosa;
00351 csincos(a, &sina, &cosa);
00352
00353
00354
00355 LPoint3 point(r * cosa, 0.0f, r * sina);
00356 vertex.add_data3(point);
00357
00358
00359
00360 PN_stdfloat b = r * _half_fov_rad;
00361 if (b >= MathNumbers::pi_f) {
00362
00363
00364 texcoord.add_data3(0, _reflect, 0);
00365
00366 } else {
00367 PN_stdfloat sinb, cosb;
00368 csincos(b, &sinb, &cosb);
00369 LPoint3 tc(sinb * cosa, cosb * _reflect, sinb * sina);
00370 texcoord.add_data3(tc);
00371 }
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 void FisheyeMaker::
00386 add_square_vertex(GeomVertexWriter &vertex, GeomVertexWriter &texcoord,
00387 PN_stdfloat a) {
00388 PN_stdfloat sina, cosa;
00389 csincos(a, &sina, &cosa);
00390
00391
00392
00393 if (cabs(sina) > cabs(cosa)) {
00394 PN_stdfloat y = (sina > 0.0f) ? _square_radius : -_square_radius;
00395 PN_stdfloat x = y * cosa / sina;
00396 LPoint3 point(x, 0.0f, y);
00397 vertex.add_data3(point);
00398
00399 } else {
00400 PN_stdfloat x = (cosa > 0.0f) ? _square_radius : -_square_radius;
00401 PN_stdfloat y = x * sina / cosa;
00402 LPoint3 point(x, 0.0f, y);
00403 vertex.add_data3(point);
00404 }
00405
00406 texcoord.add_data3(0, _reflect, 0);
00407 }
00408