15 #include "projectionScreen.h"
17 #include "transformState.h"
18 #include "workingNodePath.h"
19 #include "switchNode.h"
21 #include "geomTristrips.h"
22 #include "geomVertexWriter.h"
23 #include "geomVertexReader.h"
24 #include "geomVertexRewriter.h"
25 #include "config_distort.h"
26 #include "cullTraverserData.h"
36 ProjectionScreen(
const string &name) :
PandaNode(name)
40 _texcoord_name = InternalName::get_texcoord();
42 _has_undist_lut =
false;
43 _invert_uvs = project_invert_uvs;
46 _vignette_color.set(0.0f, 0.0f, 0.0f, 1.0f);
47 _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
48 _computed_rel_top_mat =
false;
50 _auto_recompute =
true;
70 _projector(copy._projector),
71 _projector_node(copy._projector_node),
72 _texcoord_name(copy._texcoord_name),
73 _vignette_on(copy._vignette_on),
74 _vignette_color(copy._vignette_color),
75 _frame_color(copy._frame_color),
76 _auto_recompute(copy._auto_recompute)
78 _computed_rel_top_mat =
false;
122 if (_auto_recompute) {
143 _projector = projector;
145 nassertv(projector.
node()->
is_of_type(LensNode::get_class_type()));
183 generate_screen(const
NodePath &projector, const
string &screen_name,
184 int num_x_verts,
int num_y_verts, PN_stdfloat distance,
185 PN_stdfloat fill_ratio) {
186 nassertr(!projector.is_empty() &&
187 projector.node()->is_of_type(LensNode::get_class_type()),
190 nassertr(projector_node->get_lens() != NULL, NULL);
195 rel_mat = projector.get_transform(this_np)->get_mat();
202 int num_verts = num_x_verts * num_y_verts;
203 Lens *lens = projector_node->get_lens();
204 PN_stdfloat t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
206 PN_stdfloat x_scale = 2.0f / (num_x_verts - 1);
207 PN_stdfloat y_scale = 2.0f / (num_y_verts - 1);
210 ("projectionScreen", GeomVertexFormat::get_v3n3(),
215 for (
int yi = 0; yi < num_y_verts; yi++) {
216 for (
int xi = 0; xi < num_x_verts; xi++) {
218 (PN_stdfloat)yi * y_scale - 1.0f);
224 lens->extrude(film, near_point, far_point);
225 LPoint3 point = near_point + t * (far_point - near_point);
230 lens->extrude_vec(film, norm);
232 vertex.add_data3(point * rel_mat);
233 normal.add_data3(-normalize(norm * rel_mat));
236 nassertr(vdata->get_num_rows() == num_verts, NULL);
244 for (ti = 1; ti < num_y_verts; ti++) {
246 for (si = 1; si < num_x_verts; si++) {
247 strip->add_vertex((ti - 1) * num_x_verts + (si-1));
248 strip->add_vertex(ti * num_x_verts + si);
250 strip->add_vertex((ti - 1) * num_x_verts + (num_x_verts-1));
251 strip->close_primitive();
255 geom->add_primitive(strip);
257 geom_node->add_geom(geom);
272 regenerate_screen(const
NodePath &projector, const
string &screen_name,
273 int num_x_verts,
int num_y_verts, PN_stdfloat distance,
274 PN_stdfloat fill_ratio) {
276 remove_all_children();
280 generate_screen(projector, screen_name, num_x_verts, num_y_verts,
281 distance, fill_ratio);
282 add_child(geom_node);
306 nassertr(!this_np.is_empty() && this_np.node() ==
this, NULL);
307 nassertr(!camera.is_empty() &&
308 camera.node()->is_of_type(LensNode::get_class_type()),
311 nassertr(camera_node->get_lens() != (
Lens *)NULL, NULL);
314 recompute_if_stale(this_np);
319 bool computed_rel_mat = false;
320 make_mesh_children(top, this_np, camera, rel_mat, computed_rel_mat);
341 do_recompute(this_np);
370 nassertr(!this_np.
is_empty() && this_np.
node() ==
this,
false);
372 if (_projector_node != (
LensNode *)NULL &&
373 _projector_node->get_lens() != (
Lens *)NULL) {
374 UpdateSeq lens_change = _projector_node->get_lens()->get_last_change();
375 if (_stale || lens_change != _projector_lens_change) {
381 CPT(TransformState) transform = this_np.
get_transform(_projector);
382 const LMatrix4 &top_mat = transform->get_mat();
384 _rel_top_mat = top_mat;
385 _computed_rel_top_mat =
true;
386 do_recompute(this_np);
400 void ProjectionScreen::
401 do_recompute(
const NodePath &this_np) {
402 if (_projector_node != (
LensNode *)NULL &&
403 _projector_node->get_lens() != (
Lens *)NULL) {
405 recompute_node(this_np, _rel_top_mat, _computed_rel_top_mat);
407 _computed_rel_top_mat =
false;
409 _projector_lens_change = _projector_node->get_lens()->get_last_change();
422 void ProjectionScreen::
424 bool &computed_rel_mat) {
427 recompute_geom_node(np, rel_mat, computed_rel_mat);
435 int i = DCAST(
SwitchNode, node)->get_visible_child();
438 recompute_child(
WorkingNodePath(np, child), rel_mat, computed_rel_mat);
444 for (
int i = 0; i < num_children; i++) {
446 recompute_child(
WorkingNodePath(np, child), rel_mat, computed_rel_mat);
458 void ProjectionScreen::
460 bool &computed_rel_mat) {
463 const TransformState *transform = child->get_transform();
464 if (!transform->is_identity()) {
468 bool computed_new_rel_mat =
false;
470 if (distort_cat.is_spam()) {
472 <<
"Saving rel_mat " << (
void *)&new_rel_mat <<
" at " << np <<
"\n";
475 recompute_node(np, new_rel_mat, computed_new_rel_mat);
480 recompute_node(np, rel_mat, computed_rel_mat);
489 void ProjectionScreen::
491 bool &computed_rel_mat) {
493 if (!computed_rel_mat) {
497 computed_rel_mat =
true;
499 if (distort_cat.is_spam()) {
501 <<
"Computing rel_mat " << (
void *)&rel_mat <<
" at " << np <<
"\n";
503 <<
" " << rel_mat <<
"\n";
506 if (distort_cat.is_spam()) {
508 <<
"Applying rel_mat " << (
void *)&rel_mat <<
" to " << np <<
"\n";
513 for (
int i = 0; i < num_geoms; i++) {
514 PT(
Geom) geom = node->modify_geom(i);
516 << " " << *node << " got geom " << geom
517 << ", cache_ref = " << geom->get_cache_ref_count() << "\n";
519 recompute_geom(geom, rel_mat);
531 (0.5f, 0.0f, 0.0f, 0.0f,
532 0.0f, 0.5f, 0.0f, 0.0f,
533 0.0f, 0.0f, 1.0f, 0.0f,
534 0.5f, 0.5f, 0.0f, 1.0f);
536 static const LMatrix4 lens_to_uv_inverted
537 (0.5f, 0.0f, 0.0f, 0.0f,
538 0.0f,-0.5f, 0.0f, 0.0f,
539 0.0f, 0.0f, 1.0f, 0.0f,
540 0.5f, 0.5f, 0.0f, 1.0f);
544 Lens *lens = _projector_node->get_lens();
545 nassertv(lens != (
Lens *)NULL);
547 const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
550 CPT(
GeomVertexData) vdata = geom->get_vertex_data(current_thread);
551 vdata = vdata->animate_vertices(true, current_thread);
553 CPT(GeomVertexFormat) vformat = vdata->get_format();
554 if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
556 vdata = vdata->replace_column
557 (_texcoord_name, 3, Geom::NT_stdfloat, Geom::C_texcoord);
558 geom->set_vertex_data(vdata);
560 if (_vignette_on && !vdata->has_column(InternalName::get_color())) {
562 vdata = vdata->replace_column
563 (InternalName::get_color(), 1, Geom::NT_packed_dabc, Geom::C_color);
564 geom->set_vertex_data(vdata);
573 CPT(
GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread);
577 GeomVertexReader vertex(animated_vdata, InternalName::get_vertex(), current_thread);
580 color.set_column(InternalName::get_color());
583 while (!vertex.is_at_end()) {
584 LVertex vert = vertex.get_data3();
587 LPoint3 vert3d = vert * rel_mat;
588 LPoint3 film(0.0f, 0.0f, 0.0f);
589 bool good = lens->
project(vert3d, film);
595 if (good && _has_undist_lut) {
608 uvw = LCAST(PN_stdfloat, p);
609 uvw[1] = 1.0 - uvw[1];
612 texcoord.set_data3(uvw);
618 color.set_data4(_frame_color);
620 color.set_data4(_vignette_color);
638 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
643 new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
650 new_node =
new PandaNode(node->get_name());
656 make_mesh_children(new_node, np, camera, rel_mat, computed_rel_mat);
666 void ProjectionScreen::
669 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
672 for (
int i = 0; i < num_children; i++) {
676 const TransformState *transform = child->get_transform();
677 if (!transform->is_identity()) {
681 bool computed_new_rel_mat =
false;
682 new_child = make_mesh_node(new_node,
WorkingNodePath(np, child), camera,
683 new_rel_mat, computed_new_rel_mat);
688 new_child = make_mesh_node(new_node,
WorkingNodePath(np, child), camera,
689 rel_mat, computed_rel_mat);
692 if (new_child != NULL) {
695 new_child->
set_state(child->get_state());
709 LMatrix4 &rel_mat,
bool &computed_rel_mat) {
714 if (!computed_rel_mat) {
716 NodePath true_np = np.get_node_path();
718 computed_rel_mat =
true;
721 int num_geoms = node->get_num_geoms();
722 for (
int i = 0; i < num_geoms; i++) {
723 const Geom *geom = node->get_geom(i);
725 make_mesh_geom(geom, lens_node->get_lens(), rel_mat);
726 if (new_geom != (
Geom *)NULL) {
727 new_node->add_geom(new_geom, node->get_geom_state(i));
745 (0.5f, 0.0f, 0.0f, 0.0f,
746 0.0f, 0.5f, 0.0f, 0.0f,
747 0.0f, 0.0f, 1.0f, 0.0f,
748 0.5f, 0.5f, 0.0f, 1.0f);
749 static const LMatrix4 uv_to_lens = invert(lens_to_uv);
754 new_geom->set_vertex_data(vdata->animate_vertices(false, current_thread));
755 vdata = new_geom->modify_vertex_data();
757 while (!vertex.is_at_end()) {
762 LPoint3 vert3d = vert * rel_mat;
763 LPoint3 film(0.0f, 0.0f, 0.0f);
764 bool good = lens->project(vert3d, film);
766 if (good && _has_undist_lut) {
770 LPoint3 uvw = film * lens_to_uv;
778 uvw = LCAST(PN_stdfloat, p);
779 uvw[1] = 1.0 - uvw[1];
782 film = uvw * uv_to_lens;
785 vertex.set_data3(film);
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A base class for any number of different kinds of lenses, linear and otherwise.
A node that contains a Lens.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
void set_projector(const NodePath &projector)
Specifies the LensNode that is to serve as the projector for this screen.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
void clear_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform on this node to the identity transform.
PandaNode * node() const
Returns the referenced node of the path.
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Defines a series of triangle strips.
bool calc_bilinear_point(LPoint3f &result, PN_float32 x, PN_float32 y) const
Computes the weighted average of the four nearest points to the floating-point index (x...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
This is a class designed to support low-overhead traversals of the complete scene graph...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node...
PandaNode * node() const
Returns the node traversed to so far.
void add_vertex(int vertex)
Adds the indicated vertex to the list of vertex indices used by the graphics primitive type...
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
This is a 4-by-4 transform matrix.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Sets the complete RenderState that will be applied to all nodes at this level and below...
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
bool project(const LPoint3 &point3d, LPoint3 &point2d) const
Given a 3-d point in space, determine the 2-d point this maps to, in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (-1,-1) is the lower-left corner.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
A ProjectionScreen implements a simple system for projective texturing.
void recompute()
Recomputes all the UV's for geometry below the ProjectionScreen node, as if the texture were projecte...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
A thread; that is, a lightweight process.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
bool is_empty() const
Returns true if the NodePath contains no nodes.
bool almost_equal(const LMatrix4f &other, float threshold) const
Returns true if two matrices are memberwise equal within a specified tolerance.
This is a two-component point in space.
virtual bool is_geom_node() const
A simple downcast check.
TypeHandle is the identifier used to differentiate C++ class types.
This is a sequence number that increments monotonically.
bool recompute_if_stale()
Calls recompute() only if the relative transform between the ProjectionScreen and the projector has c...
void add_child(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
A node that holds Geom objects, renderable pieces of geometry.
A node that renders only one of its children, according to the user's indication. ...
int get_num_geoms() const
Returns the number of geoms in the node.
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter, combined together into one convenient package.