Panda3D
multitexReducer.cxx
1 // Filename: multitexReducer.cxx
2 // Created by: drose (30Nov04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "multitexReducer.h"
16 #include "pandaNode.h"
17 #include "geomNode.h"
18 #include "geom.h"
19 #include "geomTransformer.h"
20 #include "accumulatedAttribs.h"
21 #include "sceneGraphReducer.h"
22 #include "renderState.h"
23 #include "transformState.h"
24 #include "graphicsOutput.h"
25 #include "displayRegion.h"
26 #include "camera.h"
27 #include "orthographicLens.h"
28 #include "cardMaker.h"
29 #include "colorAttrib.h"
30 #include "colorScaleAttrib.h"
31 #include "colorBlendAttrib.h"
32 #include "alphaTestAttrib.h"
33 #include "textureAttrib.h"
34 #include "config_grutil.h"
35 #include "config_gobj.h"
36 #include "dcast.h"
37 #include "geom.h"
38 #include "geomVertexWriter.h"
39 #include "geomVertexReader.h"
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: MultitexReducer::Constructor
43 // Access: Published
44 // Description:
45 ////////////////////////////////////////////////////////////////////
46 MultitexReducer::
47 MultitexReducer() {
48  _target_stage = TextureStage::get_default();
49  _use_geom = false;
50  _allow_tex_mat = false;
51 }
52 
53 ////////////////////////////////////////////////////////////////////
54 // Function: MultitexReducer::Destructor
55 // Access: Published
56 // Description:
57 ////////////////////////////////////////////////////////////////////
58 MultitexReducer::
59 ~MultitexReducer() {
60 }
61 
62 ////////////////////////////////////////////////////////////////////
63 // Function: MultitexReducer::clear
64 // Access: Published
65 // Description: Removes the record of nodes that were previously
66 // discovered by scan().
67 ////////////////////////////////////////////////////////////////////
69 clear() {
70  _stages.clear();
71  _geom_node_list.clear();
72 }
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: MultitexReducer::scan
76 // Access: Published
77 // Description: Starts scanning the hierarchy beginning at the
78 // indicated node. Any GeomNodes discovered in the
79 // hierarchy with multitexture will be added to internal
80 // structures in the MultitexReducer so that a future
81 // call to flatten() will operate on all of these at
82 // once.
83 //
84 // The indicated transform and state are the state
85 // inherited from the node's ancestors; any multitexture
86 // operations will be accumulated from the indicated
87 // starting state.
88 ////////////////////////////////////////////////////////////////////
90 scan(PandaNode *node, const RenderState *state, const TransformState *transform) {
91  if (grutil_cat.is_debug()) {
92  grutil_cat.debug()
93  << "scan(" << *node << ", " << *state << ", " << *transform << ")\n";
94  }
95 
96  CPT(RenderState) next_state = state->compose(node->get_state());
97  CPT(TransformState) next_transform = transform->compose(node->get_transform());
98 
99  // We must turn off any textures we come across in the scan()
100  // operation, since the flattened texture will be applied to the
101  // Geoms after the flatten() operation, and we don't want to still
102  // have a multitexture specified.
103  node->set_state(node->get_state()->remove_attrib(TextureAttrib::get_class_slot()));
104 
105  if (node->is_geom_node()) {
106  scan_geom_node(DCAST(GeomNode, node), next_state, next_transform);
107  }
108 
109  PandaNode::Children cr = node->get_children();
110  int num_children = cr.get_num_children();
111  for (int i = 0; i < num_children; i++) {
112  scan(cr.get_child(i), next_state, next_transform);
113  }
114 }
115 
116 ////////////////////////////////////////////////////////////////////
117 // Function: MultitexReducer::set_target
118 // Access: Published
119 // Description: Specifies the target TextureStage (and InternalName)
120 // that will be left on each multitexture node after the
121 // flatten operation has completed.
122 ////////////////////////////////////////////////////////////////////
125  _target_stage = stage;
126 }
127 
128 ////////////////////////////////////////////////////////////////////
129 // Function: MultitexReducer::set_use_geom
130 // Access: Published
131 // Description: Indicates whether the actual geometry will be used to
132 // generate the textures.
133 //
134 // If this is set to true, the geometry discovered by
135 // scan() will be used to generate the textures, which
136 // allows for the vertex and polygon colors to be made
137 // part of the texture itself (and makes the M_decal
138 // multitexture mode more reliable). However, this only
139 // works if the geometry does not contain multiple
140 // different polygons that map to the same UV range.
141 //
142 // If this is set to false (the default), a plain flat
143 // card will be used to generate the textures, which is
144 // more robust in general, but the resulting texture
145 // will not include vertex colors and M_decal won't work
146 // properly.
147 //
148 // Note that in case multiple sets of texture
149 // coordinates are in effect, then the additional sets
150 // will always use the geometry anyway regardless of the
151 // setting of this flag (but this will not affect vertex
152 // color).
153 ////////////////////////////////////////////////////////////////////
155 set_use_geom(bool use_geom) {
156  _use_geom = use_geom;
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: MultitexReducer::set_allow_tex_mat
161 // Access: Published
162 // Description: Indicates whether the resulting texture should be
163 // expected to be animated beyond its current range via
164 // a texture matrix (true), or whether the current range
165 // of texture coordinates will be sufficient forever
166 // (false).
167 //
168 // If this is set to true, then the entire texture image
169 // must be generated, in the assumption that the user
170 // may animate the texture around on the surface after
171 // it has been composed.
172 //
173 // If this is set to false (the default), then only the
174 // portion of the texture image which is actually in use
175 // must be generated, which may be a significant savings
176 // in texture memory.
177 ////////////////////////////////////////////////////////////////////
179 set_allow_tex_mat(bool allow_tex_mat) {
180  _allow_tex_mat = allow_tex_mat;
181 }
182 
183 ////////////////////////////////////////////////////////////////////
184 // Function: MultitexReducer::flatten
185 // Access: Published
186 // Description: Actually performs the reducing operations on the
187 // nodes that were previously scanned.
188 //
189 // A window that can be used to create texture buffers
190 // suitable for rendering this geometry must be
191 // supplied. This specifies the particular GSG that
192 // will be used to composite the textures.
193 ////////////////////////////////////////////////////////////////////
196  if (grutil_cat.is_debug()) {
197  grutil_cat.debug()
198  << "Beginning flatten operation\n";
199  Stages::const_iterator mi;
200  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
201  const StageList &stage_list = (*mi).first;
202  const GeomList &geom_list = (*mi).second;
203  grutil_cat.debug(false)
204  << "stage_list for:";
205  for (GeomList::const_iterator gi = geom_list.begin();
206  gi != geom_list.end();
207  ++gi) {
208  const GeomInfo &geom_info = (*gi);
209  grutil_cat.debug(false)
210  << " (" << geom_info._geom_node->get_name() << " g"
211  << geom_info._index << ")";
212  }
213  grutil_cat.debug(false) << ":\n";
214 
215  StageList::const_iterator si;
216  for (si = stage_list.begin(); si != stage_list.end(); ++si) {
217  const StageInfo &stage_info = (*si);
218  grutil_cat.debug(false)
219  << " " << *stage_info._stage << " " << *stage_info._tex
220  << " " << *stage_info._tex_mat << "\n";
221  }
222  }
223  }
224  Stages::const_iterator mi;
225  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
226  const StageList &stage_list = (*mi).first;
227  const GeomList &geom_list = (*mi).second;
228 
229  //determine whether this texture needs a white or transparent background
230  bool use_transparent_bg = false;
231  if(stage_list.size() > 0) {
232  if(stage_list[0]._stage->get_mode() == TextureStage::M_decal)
233  use_transparent_bg = true;
234  else
235  use_transparent_bg = false;
236  }
237  grutil_cat.debug(false) << "use transparent bg = " << use_transparent_bg << "\n";
238 
239 
240 
241  // Create an offscreen buffer in which to render the new texture.
242 
243  // Start by choosing a model TextureStage to determine the new
244  // texture's properties.
245  const StageInfo &model_stage = stage_list[choose_model_stage(stage_list)];
246 
247  Texture *model_tex = model_stage._tex;
248  int aniso_degree = model_tex->get_anisotropic_degree();
249  SamplerState::FilterType minfilter = model_tex->get_minfilter();
250  SamplerState::FilterType magfilter = model_tex->get_magfilter();
251 
252  // What is the UV range of the model stage?
253  LTexCoord min_uv, max_uv;
254  determine_uv_range(min_uv, max_uv, model_stage, geom_list);
255 
256  // Maybe we only use a small portion of the texture, or maybe we
257  // need to repeat the texture several times.
258  LVecBase2 uv_scale;
259  LVecBase2 uv_trans;
260  get_uv_scale(uv_scale, uv_trans, min_uv, max_uv);
261 
262  // Also, if there is now a scale on the UV's (in conjunction with
263  // whatever texture matrix might be applied on the model stage),
264  // we may be able to adjust the image size accordingly, to keep
265  // the pixels at about the same scale--but we have to keep it to a
266  // power of 2.
267  int x_size;
268  int y_size;
269  choose_texture_size(x_size, y_size, model_stage, uv_scale,
270  window);
271 
272  static int multitex_id = 1;
273  ostringstream multitex_name_strm;
274  multitex_name_strm << "multitex" << multitex_id;
275  multitex_id++;
276 
277  GraphicsOutput *buffer = window->make_texture_buffer
278  (multitex_name_strm.str(), x_size, y_size, NULL, false);
279 
280  // TODO: this no longer automatically deletes the buffer. We need
281  // to take care of this explicitly now.
282  buffer->set_one_shot(true);
283 
284  Texture *tex = buffer->get_texture();
285  tex->set_anisotropic_degree(aniso_degree);
286  tex->set_minfilter(minfilter);
287  tex->set_magfilter(magfilter);
288 
289  // Set up the offscreen buffer to render 0,0 to 1,1. This will be
290  // the whole texture, but nothing outside the texture.
291  DisplayRegion *dr = buffer->make_display_region();
292  PT(Camera) cam_node = new Camera("multitexCam");
293  PT(Lens) lens = new OrthographicLens();
294  lens->set_film_size(1.0f, 1.0f);
295  lens->set_film_offset(0.5f, 0.5f);
296  lens->set_near_far(-1000.0f, 1000.0f);
297  lens->set_view_mat(LMatrix4(uv_scale[0], 0.0f, 0.0, 0.0f,
298  0.0f, 1.0f, 0.0, 0.0f,
299  0.0f, 0.0f, uv_scale[1], 0.0f,
300  uv_trans[0], 0.0f, uv_trans[1], 1.0f));
301  cam_node->set_lens(lens);
302 
303  // Create a root node for the buffer's scene graph, and set up
304  // some appropriate properties for it.
305  NodePath render("buffer");
306  render.set_bin("unsorted", 0);
307  render.set_depth_test(false);
308  render.set_depth_write(false);
309  render.set_two_sided(1);
310 
311  NodePath cam = render.attach_new_node(cam_node);
312  dr->set_camera(cam);
313 
314  // If the geometry has vertex color and M_decal is in use, we must
315  // render with use_geom in effect. Otherwise we need not (and we
316  // might prefer not to).
317  bool force_use_geom = _use_geom;
318  bool bake_in_color = _use_geom;
319  LColor geom_color(1.0f, 1.0f, 1.0f, 1.0f);
320 
321  //override the base color in the transparent pass down case.
322  if(use_transparent_bg)
323  geom_color = LColor(0.0f,0.0f,0.0f,0.0f);
324 
325  if (!force_use_geom) {
326  bool uses_decal = scan_decal(stage_list);
327  if (uses_decal) {
328  // If we have M_decal, we need to bake in the flat color
329  // even if there is no vertex color.
330  bake_in_color = true;
331 
332  /*
333  int num_colors = 0;
334  scan_color(geom_list, geom_color, num_colors);
335 
336  if (num_colors > 1) {
337  // But if there is also vertex color, then we need to render
338  // with the geometry.
339  force_use_geom = true;
340  }*/
341  }
342  }
343 
344  if (!force_use_geom) {
345  // Put one plain white (or flat-colored) card in the background
346  // for the first texture layer to apply onto.
347 
348  CardMaker cm("background");
349  cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]);
350  if (bake_in_color) {
351  cm.set_color(geom_color);
352  }
353  render.attach_new_node(cm.generate());
354 
355  } else {
356  // Put a vertex-colored model of the geometry in the background
357  // for the first texture layer to apply only.
358  nassertv(bake_in_color);
359  PT(GeomNode) geom_node = new GeomNode("background");
360  transfer_geom(geom_node, NULL, geom_list, true);
361 
362  render.attach_new_node(geom_node);
363  }
364 
365  StageList::const_iterator si;
366  for (si = stage_list.begin(); si != stage_list.end(); ++si) {
367  const StageInfo &stage_info = (*si);
368 
369  make_texture_layer(render, stage_info, geom_list,
370  min_uv, max_uv, force_use_geom, use_transparent_bg);
371  }
372 
373  // Now modify the geometry to apply the new texture, instead of
374  // the old multitexture.
375  CPT(RenderAttrib) new_ta = DCAST(TextureAttrib, TextureAttrib::make())->
376  add_on_stage(_target_stage, tex);
377 
378  GeomList::const_iterator gi;
379  for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
380  const GeomInfo &geom_info = (*gi);
381 
382  CPT(RenderState) geom_state =
383  geom_info._geom_node->get_geom_state(geom_info._index);
384  int override = geom_info._geom_net_state->get_override(TextureAttrib::get_class_slot());
385  geom_state = geom_state->add_attrib(new_ta, override);
386 
387  if (bake_in_color) {
388  // If we have baked the color into the texture, we have to be
389  // sure to disable coloring on the new fragment.
390  geom_state = geom_state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)));
391 
392  // And we invent a ColorScaleAttrib to undo the effect of any
393  // color scale we're getting from above. This is not the same
394  // thing as a ColorScaleAttrib::make_off(), since that would
395  // prohibit any future changes to the color scale.
396  const RenderAttrib *attrib =
397  geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
398 
399  if (attrib != (const RenderAttrib *)NULL) {
400  geom_state = geom_state->add_attrib
401  (attrib->invert_compose(ColorScaleAttrib::make_identity()));
402  }
403  }
404 
405  // Determine what tex matrix should be on the Geom.
406  CPT(TransformState) tex_mat = TransformState::make_identity();
407 
408  const RenderAttrib *ra = geom_info._state->get_attrib(TexMatrixAttrib::get_class_slot());
409  if (ra != (const RenderAttrib *)NULL) {
410  // There is a texture matrix inherited from above; put an
411  // inverse matrix on the Geom to compensate.
412  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, ra);
413  CPT(TransformState) tex_mat = tma->get_transform(_target_stage);
414  }
415 
416  tex_mat = tex_mat->compose(TransformState::make_pos_hpr_scale
417  (LVecBase3(uv_trans[0], uv_trans[1], 0.0f),
418  LVecBase3(0.0f, 0.0f, 0.0f),
419  LVecBase3(uv_scale[0], uv_scale[1], 1.0f)));
420 
421  if (tex_mat->is_identity()) {
422  // There should be no texture matrix on the Geom.
423  geom_state = geom_state->remove_attrib(TexMatrixAttrib::get_class_slot());
424  } else {
425  // The texture matrix should be as computed.
426  CPT(RenderAttrib) new_tma = TexMatrixAttrib::make
427  (_target_stage, tex_mat->invert_compose(TransformState::make_identity()));
428  geom_state = geom_state->add_attrib(new_tma);
429  }
430 
431 
432  geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
433  }
434  }
435 
436  // Now that we've copied all of the geometry and applied texture
437  // matrices, flatten out those texture matrices where possible.
438  GeomTransformer transformer;
439 
440  GeomNodeList::const_iterator gni;
441  for (gni = _geom_node_list.begin(); gni != _geom_node_list.end(); ++gni) {
442  const GeomNodeInfo &geom_node_info = (*gni);
443  AccumulatedAttribs attribs;
444  attribs._texture =
445  geom_node_info._state->get_attrib(TextureAttrib::get_class_slot());
446  geom_node_info._geom_node->apply_attribs_to_vertices
447  (attribs, SceneGraphReducer::TT_tex_matrix, transformer);
448  }
449 }
450 
451 ////////////////////////////////////////////////////////////////////
452 // Function: MultitexReducer::scan_geom_node
453 // Access: Private
454 // Description: Adds the Geoms in the indicated GeomNode to the
455 // internal database of multitexture elements.
456 ////////////////////////////////////////////////////////////////////
457 void MultitexReducer::
458 scan_geom_node(GeomNode *node, const RenderState *state,
459  const TransformState *transform) {
460  if (grutil_cat.is_debug()) {
461  grutil_cat.debug()
462  << "scan_geom_node(" << *node << ", " << *state << ", "
463  << *transform << ")\n";
464  }
465 
466  _geom_node_list.push_back(GeomNodeInfo(state, node));
467 
468  int num_geoms = node->get_num_geoms();
469  for (int gi = 0; gi < num_geoms; gi++) {
470  CPT(RenderState) geom_net_state =
471  state->compose(node->get_geom_state(gi));
472 
473  if (grutil_cat.is_debug()) {
474  grutil_cat.debug()
475  << "geom " << gi << " net_state =\n";
476  geom_net_state->write(cerr, 2);
477  }
478 
479  // Get out the net TextureAttrib and TexMatrixAttrib from the state.
480  const RenderAttrib *attrib;
481  const TextureAttrib *ta = NULL;
482 
483  attrib = geom_net_state->get_attrib(TextureAttrib::get_class_slot());
484  if (attrib != (const RenderAttrib *)NULL) {
485  ta = DCAST(TextureAttrib, attrib);
486  }
487 
488  if (ta == (TextureAttrib *)NULL) {
489  // No texture should be on the Geom.
490  CPT(RenderState) geom_state = node->get_geom_state(gi);
491  geom_state = geom_state->remove_attrib(TextureAttrib::get_class_slot());
492  node->set_geom_state(gi, geom_state);
493 
494  } else if (ta->get_num_on_stages() < 2) {
495  // Just a single texture on the Geom; we don't really need to do
496  // anything to flatten the textures, then. But we should ensure
497  // that the correct TextureAttrib is applied to the Geom.
498  int override = geom_net_state->get_override(TextureAttrib::get_class_slot());
499  CPT(RenderState) geom_state = node->get_geom_state(gi);
500  geom_state = geom_state->add_attrib(ta, override);
501  node->set_geom_state(gi, geom_state);
502 
503  } else {
504  // Ok, we have multitexture. Record the Geom.
505  CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
506  attrib = geom_net_state->get_attrib(TexMatrixAttrib::get_class_slot());
507  if (attrib != (const RenderAttrib *)NULL) {
508  tma = DCAST(TexMatrixAttrib, attrib);
509  }
510 
511  StageList stage_list;
512 
513  int num_stages = ta->get_num_on_stages();
514  for (int si = 0; si < num_stages; si++) {
515  TextureStage *stage = ta->get_on_stage(si);
516  Texture *tex = ta->get_on_texture(stage);
517  if (tex->get_x_size() != 0 && tex->get_y_size() != 0) {
518  stage_list.push_back(StageInfo(stage, ta, tma));
519 
520  } else {
521  grutil_cat.info()
522  << "Ignoring invalid texture stage " << stage->get_name() << "\n";
523  }
524  }
525 
526  if (stage_list.size() >= 2) {
527  record_stage_list(stage_list, GeomInfo(state, geom_net_state, node, gi));
528  }
529  }
530  }
531 }
532 
533 ////////////////////////////////////////////////////////////////////
534 // Function: MultitexReducer::record_stage_list
535 // Access: Private
536 // Description: Adds the record of this one Geom and its associated
537 // StageList.
538 ////////////////////////////////////////////////////////////////////
539 void MultitexReducer::
540 record_stage_list(const MultitexReducer::StageList &stage_list,
541  const MultitexReducer::GeomInfo &geom_info) {
542  if (grutil_cat.is_debug()) {
543  grutil_cat.debug()
544  << "record_stage_list for " << geom_info._geom_node->get_name() << " g"
545  << geom_info._index << ":\n";
546  StageList::const_iterator si;
547  for (si = stage_list.begin(); si != stage_list.end(); ++si) {
548  const StageInfo &stage_info = (*si);
549  grutil_cat.debug(false)
550  << " " << *stage_info._stage << " " << *stage_info._tex
551  << " " << *stage_info._tex_mat << "\n";
552  }
553  }
554 
555  _stages[stage_list].push_back(geom_info);
556 }
557 
558 ////////////////////////////////////////////////////////////////////
559 // Function: MultitexReducer::choose_model_stage
560 // Access: Private
561 // Description: Chooses one of the TextureStages in the stage_list to
562 // serve as the model to determine the size and
563 // properties of the resulting texture.
564 ////////////////////////////////////////////////////////////////////
565 size_t MultitexReducer::
566 choose_model_stage(const MultitexReducer::StageList &stage_list) const {
567  for (size_t si = 0; si < stage_list.size(); si++) {
568  const StageInfo &stage_info = stage_list[si];
569  if (stage_info._stage == _target_stage) {
570  // If we find the target stage, use that.
571  return si;
572  }
573  }
574 
575  // If none of the stages are the target stage, use the bottom image.
576  return 0;
577 }
578 
579 ////////////////////////////////////////////////////////////////////
580 // Function: MultitexReducer::determine_uv_range
581 // Access: Private
582 // Description: Determines what the effective UV range for the
583 // indicated texture is across its geoms. Returns true
584 // if any UV's are found, false otherwise.
585 ////////////////////////////////////////////////////////////////////
586 bool MultitexReducer::
587 determine_uv_range(LTexCoord &min_uv, LTexCoord &max_uv,
588  const MultitexReducer::StageInfo &model_stage,
589  const MultitexReducer::GeomList &geom_list) const {
590  const InternalName *model_name = model_stage._stage->get_texcoord_name();
591  bool got_any = false;
592 
593  GeomList::const_iterator gi;
594  for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
595  const GeomInfo &geom_info = (*gi);
596 
597  PT(Geom) geom =
598  geom_info._geom_node->get_geom(geom_info._index)->make_copy();
599 
600  CPT(GeomVertexData) vdata = geom->get_vertex_data();
601  CPT(GeomVertexFormat) format = vdata->get_format();
602  if (format->has_column(model_name)) {
603  GeomVertexReader texcoord(vdata, model_name);
604 
605  if (!texcoord.is_at_end()) {
606  const LVecBase2 &uv = texcoord.get_data2();
607  if (!got_any) {
608  min_uv = max_uv = uv;
609  got_any = true;
610 
611  } else {
612  min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
613  max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
614  }
615 
616  while (!texcoord.is_at_end()) {
617  const LVecBase2 &uv = texcoord.get_data2();
618  min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
619  max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
620  }
621  }
622  }
623  }
624 
625  if (!got_any) {
626  min_uv.set(0.0f, 0.0f);
627  max_uv.set(1.0f, 1.0f);
628  }
629 
630  return got_any;
631 }
632 
633 ////////////////////////////////////////////////////////////////////
634 // Function: MultitexReducer::get_uv_scale
635 // Access: Private
636 // Description: Chooses an appropriate transform to apply to all of
637 // the UV's on the generated texture, based on the
638 // coverage of the model stage. If only a portion of
639 // the model stage is used, we scale the UV's up to zoom
640 // into that one portion; on the other hand, if the
641 // texture repeats many times, we scale the UV's down to
642 // to include all of the repeating image.
643 ////////////////////////////////////////////////////////////////////
644 void MultitexReducer::
645 get_uv_scale(LVecBase2 &uv_scale, LVecBase2 &uv_trans,
646  const LTexCoord &min_uv, const LTexCoord &max_uv) const {
647  if (max_uv[0] != min_uv[0]) {
648  uv_scale[0] = (max_uv[0] - min_uv[0]);
649  } else {
650  uv_scale[0] = 1.0f;
651  }
652 
653  if (max_uv[1] != min_uv[1]) {
654  uv_scale[1] = (max_uv[1] - min_uv[1]);
655  } else {
656  uv_scale[1] = 1.0f;
657  }
658 
659  uv_trans[0] = (min_uv[0] + max_uv[0]) / 2.0f - uv_scale[0] * 0.5f;
660  uv_trans[1] = (min_uv[1] + max_uv[1]) / 2.0f - uv_scale[1] * 0.5f;
661 }
662 
663 ////////////////////////////////////////////////////////////////////
664 // Function: MultitexReducer::choose_texture_size
665 // Access: Private
666 // Description: Chooses an appropriate size to make the new texture,
667 // based on the size of the original model stage's
668 // texture, and the scale applied to the UV's.
669 ////////////////////////////////////////////////////////////////////
670 void MultitexReducer::
671 choose_texture_size(int &x_size, int &y_size,
672  const MultitexReducer::StageInfo &model_stage,
673  const LVecBase2 &uv_scale,
674  GraphicsOutput *window) const {
675  Texture *model_tex = model_stage._tex;
676 
677  // Start with the same size as the model texture.
678  x_size = model_tex->get_x_size();
679  y_size = model_tex->get_y_size();
680 
681  // But we might be looking at just a subset of that texture (|scale| <
682  // 1) or a superset of the texture (|scale| > 1). In this case, we
683  // should adjust the pixel size accordingly, although we have to
684  // keep it to a power of 2.
685 
686  LVecBase3 inherited_scale = model_stage._tex_mat->get_scale();
687 
688  PN_stdfloat u_scale = cabs(inherited_scale[0]) * uv_scale[0];
689  if (u_scale != 0.0f) {
690  while (u_scale >= 2.0f) {
691  x_size *= 2;
692  u_scale *= 0.5f;
693  }
694  while (u_scale <= 0.5f && x_size > 0) {
695  x_size /= 2;
696  u_scale *= 2.0f;
697  }
698  }
699 
700  PN_stdfloat v_scale = cabs(inherited_scale[1]) * uv_scale[1];
701  if (v_scale != 0.0f) {
702  while (v_scale >= 2.0f) {
703  y_size *= 2;
704  v_scale *= 0.5f;
705  }
706  while (v_scale <= 0.5f && y_size > 0) {
707  y_size /= 2;
708  v_scale *= 2.0f;
709  }
710  }
711 
712  if (x_size == 0 || y_size == 0) {
713  grutil_cat.warning()
714  << "Texture size " << model_tex->get_x_size() << " "
715  << model_tex->get_y_size() << " with scale "
716  << model_stage._tex_mat->get_scale() << ", reduced to size "
717  << x_size << " " << y_size << "; constraining to 1 1.\n";
718  x_size = 1;
719  y_size = 1;
720  }
721 
722  // Constrain the x_size and y_size to the max_texture_dimension.
723  if (max_texture_dimension > 0) {
724  x_size = min(x_size, (int)max_texture_dimension);
725  y_size = min(y_size, (int)max_texture_dimension);
726  }
727 
728  // Finally, make sure the new sizes fit within the window, so we can
729  // use a parasite buffer.
730  int win_x_size = window->get_x_size();
731  if (win_x_size != 0 && x_size > win_x_size) {
732  x_size /= 2;
733  while (x_size > win_x_size) {
734  x_size /= 2;
735  }
736  }
737 
738  int win_y_size = window->get_y_size();
739  if (win_y_size != 0 && y_size > win_y_size) {
740  y_size /= 2;
741  while (y_size > win_y_size) {
742  y_size /= 2;
743  }
744  }
745 }
746 
747 ////////////////////////////////////////////////////////////////////
748 // Function: MultitexReducer::make_texture_layer
749 // Access: Private
750 // Description: Creates geometry to render the texture into the
751 // offscreen buffer using the same effects that were
752 // requested by its multitexture specification.
753 ////////////////////////////////////////////////////////////////////
754 void MultitexReducer::
755 make_texture_layer(const NodePath &render,
756  const MultitexReducer::StageInfo &stage_info,
757  const MultitexReducer::GeomList &geom_list,
758  const LTexCoord &min_uv, const LTexCoord &max_uv,
759  bool force_use_geom, bool transparent_base) {
760  CPT(RenderAttrib) cba;
761 
762  switch (stage_info._stage->get_mode()) {
763  case TextureStage::M_normal:
764  case TextureStage::M_normal_height:
765  case TextureStage::M_glow:
766  case TextureStage::M_gloss:
767  case TextureStage::M_height:
768  case TextureStage::M_selector:
769  case TextureStage::M_normal_gloss:
770  // Don't know what to do with these funny modes. We should
771  // probably raise an exception or something. Fall through for
772  // now.
773 
774  case TextureStage::M_modulate_glow:
775  case TextureStage::M_modulate_gloss:
776  case TextureStage::M_modulate:
777  cba = ColorBlendAttrib::make
778  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
779  ColorBlendAttrib::O_zero);
780  break;
781 
782  case TextureStage::M_decal:
783  if(transparent_base) {
784  cba = AlphaTestAttrib::make
785  (AlphaTestAttrib::M_greater, 0.0f);
786  } else {
787  cba = ColorBlendAttrib::make
788  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_incoming_alpha,
789  ColorBlendAttrib::O_one_minus_incoming_alpha);
790  }
791  break;
792 
793  case TextureStage::M_blend:
794  cba = ColorBlendAttrib::make
795  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
796  ColorBlendAttrib::O_one_minus_incoming_color,
797  stage_info._stage->get_color());
798  break;
799 
800  case TextureStage::M_replace:
801  cba = ColorBlendAttrib::make_off();
802  break;
803 
804  case TextureStage::M_add:
805  cba = ColorBlendAttrib::make
806  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_one,
807  ColorBlendAttrib::O_one);
808  break;
809 
810  case TextureStage::M_combine:
811  // We only support certain modes of M_combine.
812  switch (stage_info._stage->get_combine_rgb_mode()) {
813  case TextureStage::CM_modulate:
814  {
815  TextureStage::CombineSource source0 = stage_info._stage->get_combine_rgb_source0();
816  TextureStage::CombineOperand operand0 = stage_info._stage->get_combine_rgb_operand0();
817  TextureStage::CombineSource source1 = stage_info._stage->get_combine_rgb_source1();
818  TextureStage::CombineOperand operand1 = stage_info._stage->get_combine_rgb_operand1();
819  // Since modulate doesn't care about order, let's establish
820  // the convention that the lowest-numbered source
821  // operand is in slot 0 (just for purposes of comparison).
822  if (source1 < source0) {
823  source0 = stage_info._stage->get_combine_rgb_source1();
824  operand0 = stage_info._stage->get_combine_rgb_operand1();
825  source1 = stage_info._stage->get_combine_rgb_source0();
826  operand1 = stage_info._stage->get_combine_rgb_operand0();
827  }
828 
829  if (source0 == TextureStage::CS_primary_color &&
830  source1 == TextureStage::CS_previous) {
831  // This is just a trick to re-apply the vertex (lighting)
832  // color on the top of the texture stack. We can ignore it,
833  // since the flattened texture will do this anyway.
834  return;
835 
836  } else if (source0 == TextureStage::CS_texture &&
837  source1 == TextureStage::CS_constant) {
838  // Scaling the texture by a flat color.
839  cba = ColorBlendAttrib::make
840  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
841  ColorBlendAttrib::O_zero, stage_info._stage->get_color());
842 
843  } else if (source0 == TextureStage::CS_texture &&
844  source1 == TextureStage::CS_previous) {
845  // Just an ordinary modulate.
846  cba = ColorBlendAttrib::make
847  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
848  ColorBlendAttrib::O_zero);
849 
850  } else {
851  // Some other kind of modulate; we don't support it.
852  return;
853  }
854  }
855  break;
856 
857  default:
858  // Ignore this stage; we don't support it.
859  return;
860  }
861  break;
862 
863  case TextureStage::M_blend_color_scale:
864  // TODO: make a distinction between this and M_blend.
865  cba = ColorBlendAttrib::make
866  (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
867  ColorBlendAttrib::O_one_minus_incoming_color,
868  stage_info._stage->get_color());
869  break;
870  }
871 
872  NodePath geom;
873 
874  if (!force_use_geom && stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
875  // If this TextureStage uses the target texcoords, we can just
876  // generate a simple card the fills the entire buffer.
877  CardMaker cm(stage_info._tex->get_name());
878  cm.set_uv_range(min_uv, max_uv);
879  cm.set_has_uvs(true);
880  cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]);
881 
882  geom = render.attach_new_node(cm.generate());
883 
884  } else {
885  // If this TextureStage uses some other texcoords (or if use_geom
886  // is true), we have to generate geometry that maps the texcoords
887  // to the target space. This will work only for very simple cases
888  // where the geometry is not too extensive and doesn't repeat over
889  // the same UV's.
890  PT(GeomNode) geom_node = new GeomNode(stage_info._tex->get_name());
891  transfer_geom(geom_node, stage_info._stage->get_texcoord_name(),
892  geom_list, false);
893 
894  geom = render.attach_new_node(geom_node);
895 
896  geom.set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
897  }
898 
899  if (!stage_info._tex_mat->is_identity()) {
900  geom.set_tex_transform(TextureStage::get_default(), stage_info._tex_mat);
901  }
902 
903  geom.set_texture(stage_info._tex);
904  geom.node()->set_attrib(cba);
905 }
906 
907 ////////////////////////////////////////////////////////////////////
908 // Function: MultitexReducer::transfer_geom
909 // Access: Private
910 // Description: Copy the vertices from the indicated geom_list,
911 // mapping the vertex coordinates so that the geometry
912 // will render the appropriate distortion on the texture
913 // to map UV's from the specified set of texture
914 // coordinates to the target set.
915 ////////////////////////////////////////////////////////////////////
916 void MultitexReducer::
917 transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
918  const MultitexReducer::GeomList &geom_list,
919  bool preserve_color) {
920  Thread *current_thread = Thread::get_current_thread();
921  GeomList::const_iterator gi;
922  for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
923  const GeomInfo &geom_info = (*gi);
924  const Geom *orig_geom = geom_info._geom_node->get_geom(geom_info._index);
925 
926  // Copy the Geom. This actually performs just a pointer copy of
927  // the original GeomVertexData and other associated structures.
928  PT(Geom) geom = orig_geom->make_copy();
929 
930  // Ensure that any vertex animation has been applied.
931  geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread));
932 
933  // Now get a modifiable pointer to the vertex data in the new
934  // Geom. This will actually perform a deep copy of the vertex
935  // data.
936  PT(GeomVertexData) vdata = geom->modify_vertex_data();
937  vdata->set_usage_hint(Geom::UH_stream);
938 
939  if (vdata->has_column(_target_stage->get_texcoord_name())) {
940  GeomVertexWriter vertex(vdata, InternalName::get_vertex(), current_thread);
941  GeomVertexReader texcoord(vdata, _target_stage->get_texcoord_name(), current_thread);
942 
943  while (!texcoord.is_at_end()) {
944  const LVecBase2 &tc = texcoord.get_data2();
945  vertex.set_data3(tc[0], 0.0f, tc[1]);
946  }
947  }
948 
949  if (texcoord_name != (const InternalName *)NULL &&
950  texcoord_name != InternalName::get_texcoord()) {
951  // Copy the texture coordinates from the indicated name over
952  // to the default name.
953  const GeomVertexColumn *column =
954  vdata->get_format()->get_column(texcoord_name);
955  if (column != (const GeomVertexColumn *)NULL) {
956  vdata = vdata->replace_column
957  (InternalName::get_texcoord(), column->get_num_components(),
958  column->get_numeric_type(), column->get_contents());
959  geom->set_vertex_data(vdata);
960 
961  GeomVertexReader from(vdata, texcoord_name, current_thread);
962  GeomVertexWriter to(vdata, InternalName::get_texcoord(), current_thread);
963  while (!from.is_at_end()) {
964  to.add_data2(from.get_data2());
965  }
966  }
967  }
968 
969  CPT(RenderState) geom_state = RenderState::make_empty();
970  if (preserve_color) {
971  // Be sure to preserve whatever colors are on the geom.
972  const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_slot());
973  if (ca != (const RenderAttrib *)NULL) {
974  geom_state = geom_state->add_attrib(ca);
975  }
976  const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
977  if (csa != (const RenderAttrib *)NULL) {
978  geom_state = geom_state->add_attrib(csa);
979  }
980  }
981 
982  geom_node->add_geom(geom, geom_state);
983  }
984 }
985 
986 ////////////////////////////////////////////////////////////////////
987 // Function: MultitexReducer::scan_color
988 // Access: Private
989 // Description: Checks all the geoms in the list to see if they all
990 // use flat color, or if there is per-vertex color in
991 // use.
992 //
993 // Assumption: num_colors = 0 on entry. On exit,
994 // num_colors = 1 if there is exactly one color in use,
995 // or 2 if there is more than one color in use. If
996 // num_colors = 1, then geom_color is filled in with the
997 // color in use.
998 ////////////////////////////////////////////////////////////////////
999 void MultitexReducer::
1000 scan_color(const MultitexReducer::GeomList &geom_list, LColor &geom_color,
1001  int &num_colors) const {
1002  GeomList::const_iterator gi;
1003  for (gi = geom_list.begin(); gi != geom_list.end() && num_colors < 2; ++gi) {
1004  const GeomInfo &geom_info = (*gi);
1005 
1006  LColor flat_color;
1007  bool has_flat_color = false;
1008  bool has_vertex_color = false;
1009 
1010  LColor color_scale(1.0f, 1.0f, 1.0f, 1.0f);
1011  const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
1012  if (csa != (const RenderAttrib *)NULL) {
1013  const ColorScaleAttrib *a = DCAST(ColorScaleAttrib, csa);
1014  if (a->has_scale()) {
1015  color_scale = a->get_scale();
1016  }
1017  }
1018 
1019  ColorAttrib::Type color_type = ColorAttrib::T_vertex;
1020  const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_slot());
1021  if (ca != (const RenderAttrib *)NULL) {
1022  color_type = DCAST(ColorAttrib, ca)->get_color_type();
1023  }
1024 
1025  if (color_type == ColorAttrib::T_flat) {
1026  // This geom has a flat color attrib, which overrides the vertices.
1027  flat_color = DCAST(ColorAttrib, ca)->get_color();
1028  has_flat_color = true;
1029 
1030  } else if (color_type == ColorAttrib::T_vertex) {
1031  // This geom gets its color from its vertices.
1032  const Geom *geom = geom_info._geom_node->get_geom(geom_info._index);
1033  if (geom->get_vertex_data()->has_column(InternalName::get_color())) {
1034  // This geom has per-vertex color. Assume the colors in the
1035  // table are actually different from each other.
1036  has_vertex_color = true;
1037  }
1038  }
1039 
1040  if (has_vertex_color) {
1041  num_colors = 2;
1042 
1043  } else if (has_flat_color) {
1044  flat_color.set(flat_color[0] * color_scale[0],
1045  flat_color[1] * color_scale[1],
1046  flat_color[2] * color_scale[2],
1047  flat_color[3] * color_scale[3]);
1048 
1049  if (num_colors == 0) {
1050  num_colors = 1;
1051  geom_color = flat_color;
1052 
1053  } else if (!flat_color.almost_equal(geom_color)) {
1054  // Too bad; there are multiple colors.
1055  num_colors = 2;
1056  }
1057  }
1058  }
1059 }
1060 
1061 ////////////////////////////////////////////////////////////////////
1062 // Function: MultitexReducer::scan_decal
1063 // Access: Private
1064 // Description: Checks all the stages in the list to see if any of
1065 // them apply a texture via M_decal. Returns true if
1066 // so, false otherwise.
1067 ////////////////////////////////////////////////////////////////////
1068 bool MultitexReducer::
1069 scan_decal(const MultitexReducer::StageList &stage_list) const {
1070  StageList::const_iterator si;
1071  for (si = stage_list.begin(); si != stage_list.end(); ++si) {
1072  const StageInfo &stage_info = (*si);
1073 
1074  if (stage_info._stage->get_mode() == TextureStage::M_decal) {
1075  return true;
1076  }
1077  }
1078 
1079  return false;
1080 }
1081 
1082 
1083 ////////////////////////////////////////////////////////////////////
1084 // Function: MultitexReducer::StageInfo::Constructor
1085 // Access: Public
1086 // Description:
1087 ////////////////////////////////////////////////////////////////////
1088 MultitexReducer::StageInfo::
1089 StageInfo(TextureStage *stage, const TextureAttrib *ta,
1090  const TexMatrixAttrib *tma) :
1091  _stage(stage),
1092  _tex_mat(TransformState::make_identity())
1093 {
1094  _tex = ta->get_on_texture(_stage);
1095  if (tma->has_stage(stage)) {
1096  _tex_mat = tma->get_transform(stage);
1097  }
1098 }
1099 
const RenderState * get_geom_state(int n) const
Returns the RenderState associated with the nth geom of the node.
Definition: geomNode.I:106
bool has_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
int get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:1163
void set_depth_test(bool depth_test, int priority=0)
Specifically sets or disables the testing of the depth buffer on this particular node.
Definition: nodePath.cxx:5212
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the color of the card.
Definition: cardMaker.I:113
void set_one_shot(bool one_shot)
Changes the current setting of the one-shot flag.
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
Contents get_contents() const
Returns the token representing the semantic meaning of the stored value.
virtual Texture * get_texture(int i=0) const
Returns the nth texture into which the GraphicsOutput renders.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
int get_anisotropic_degree() const
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition: texture.I:1211
void set_depth_write(bool depth_write, int priority=0)
Specifically sets or disables the writing to the depth buffer on this particular node.
Definition: nodePath.cxx:5282
void set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the size of the card.
Definition: cardMaker.I:65
void set_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row. ...
void scan(const NodePath &node)
Starts scanning the hierarchy beginning at the indicated node.
const LVecBase4 & get_scale() const
Returns the scale to be applied to colors.
void set_target(TextureStage *stage)
Specifies the target TextureStage (and InternalName) that will be left on each multitexture node afte...
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
const LVecBase2 & get_data2()
Returns the data associated with the read row, expressed as a 2-component value, and advances the rea...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
int get_y_size() const
Returns the visible height of the window or buffer, if it is known.
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row. ...
SamplerState::FilterType get_magfilter() const
Returns the filter mode of the texture for magnification.
Definition: texture.I:1157
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Applies a scene-graph color to the referenced node.
Definition: nodePath.cxx:2270
void set_magfilter(FilterType filter)
Sets the filtering method that should be used when viewing the texture up close.
Definition: texture.I:967
int get_num_geoms() const
Returns the number of geoms in the node.
Definition: geomNode.I:46
DisplayRegion * make_display_region()
Creates a new DisplayRegion that covers the entire window.
This defines how a single column is interleaved within a vertex array stored within a Geom...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
Definition: nodePath.cxx:3346
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
void flatten(GraphicsOutput *window)
Actually performs the reducing operations on the nodes that were previously scanned.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
void set_bin(const string &bin_name, int draw_order, int priority=0)
Assigns the geometry at this level and below to the named rendering bin.
Definition: nodePath.cxx:3263
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:118
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:723
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
bool almost_equal(const LVecBase4f &other, float threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
Definition: lvecBase4.h:1339
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
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...
Definition: pandaNode.cxx:1216
This is the base class for all two-component vectors and points.
Definition: lvecBase2.h:105
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
void clear()
Removes the record of nodes that were previously discovered by scan().
This class generates 2-d "cards", that is, rectangular polygons, particularly useful for showing text...
Definition: cardMaker.h:32
void set_tex_transform(TextureStage *stage, const TransformState *transform)
Sets the texture matrix on the current node to the indicated transform for the given stage...
Definition: nodePath.cxx:3926
This is a base class for the various different classes that represent the result of a frame of render...
int get_x_size() const
Returns the visible width of the window or buffer, if it is known.
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:1107
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
const string & get_name() const
Returns the name of this texture stage.
Definition: textureStage.I:32
An orthographic lens.
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
Applies a transform matrix to UV&#39;s before they are rendered.
void set_anisotropic_degree(int anisotropic_degree)
Specifies the level of anisotropic filtering to apply to the texture.
Definition: texture.I:990
virtual void set_camera(const NodePath &camera)
Sets the camera that is associated with this DisplayRegion.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:773
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom&#39;s underlying vertex data table with a completely new table.
Definition: geom.cxx:183
A thread; that is, a lightweight process.
Definition: thread.h:51
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
int get_y_size() const
Returns the height of the texture image in texels.
Definition: texture.I:650
bool is_at_end() const
Returns true if the reader is currently at the end of the list of vertices, false otherwise...
void set_minfilter(FilterType filter)
Sets the filtering method that should be used when viewing the texture from a distance.
Definition: texture.I:951
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:61
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.I:91
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:30
void set_allow_tex_mat(bool allow_tex_mat)
Indicates whether the resulting texture should be expected to be animated beyond its current range vi...
This is a two-component point in space.
Definition: lpoint2.h:92
void set_geom_state(int n, const RenderState *state)
Changes the RenderState associated with the nth geom of the node.
Definition: geomNode.I:131
PandaNode * get_child(int n) const
Returns the nth child of the node.
Definition: pandaNode.I:1174
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:37
static TextureStage * get_default()
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.I:766
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2486
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
void set_two_sided(bool two_sided, int priority=0)
Specifically sets or disables two-sided rendering mode on this particular node.
Definition: nodePath.cxx:5135
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
SamplerState::FilterType get_minfilter() const
Returns the filter mode of the texture for minification.
Definition: texture.I:1139
void add_geom(Geom *geom, const RenderState *state=RenderState::make_empty())
Adds a new Geom to the node.
Definition: geomNode.cxx:642
int get_x_size() const
Returns the width of the texture image in texels.
Definition: texture.I:638
void set_use_geom(bool use_geom)
Indicates whether the actual geometry will be used to generate the textures.
An object specifically designed to transform the vertices of a Geom without disturbing indexing or af...