00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "multitexReducer.h"
00016 #include "pandaNode.h"
00017 #include "geomNode.h"
00018 #include "geom.h"
00019 #include "geomTransformer.h"
00020 #include "accumulatedAttribs.h"
00021 #include "sceneGraphReducer.h"
00022 #include "renderState.h"
00023 #include "transformState.h"
00024 #include "graphicsOutput.h"
00025 #include "displayRegion.h"
00026 #include "camera.h"
00027 #include "orthographicLens.h"
00028 #include "cardMaker.h"
00029 #include "colorAttrib.h"
00030 #include "colorScaleAttrib.h"
00031 #include "colorBlendAttrib.h"
00032 #include "alphaTestAttrib.h"
00033 #include "textureAttrib.h"
00034 #include "config_grutil.h"
00035 #include "config_gobj.h"
00036 #include "dcast.h"
00037 #include "geom.h"
00038 #include "geomVertexWriter.h"
00039 #include "geomVertexReader.h"
00040
00041
00042
00043
00044
00045
00046 MultitexReducer::
00047 MultitexReducer() {
00048 _target_stage = TextureStage::get_default();
00049 _use_geom = false;
00050 _allow_tex_mat = false;
00051 }
00052
00053
00054
00055
00056
00057
00058 MultitexReducer::
00059 ~MultitexReducer() {
00060 }
00061
00062
00063
00064
00065
00066
00067
00068 void MultitexReducer::
00069 clear() {
00070 _stages.clear();
00071 _geom_node_list.clear();
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 void MultitexReducer::
00090 scan(PandaNode *node, const RenderState *state, const TransformState *transform) {
00091 if (grutil_cat.is_debug()) {
00092 grutil_cat.debug()
00093 << "scan(" << *node << ", " << *state << ", " << *transform << ")\n";
00094 }
00095
00096 CPT(RenderState) next_state = state->compose(node->get_state());
00097 CPT(TransformState) next_transform = transform->compose(node->get_transform());
00098
00099
00100
00101
00102
00103 node->set_state(node->get_state()->remove_attrib(TextureAttrib::get_class_slot()));
00104
00105 if (node->is_geom_node()) {
00106 scan_geom_node(DCAST(GeomNode, node), next_state, next_transform);
00107 }
00108
00109 PandaNode::Children cr = node->get_children();
00110 int num_children = cr.get_num_children();
00111 for (int i = 0; i < num_children; i++) {
00112 scan(cr.get_child(i), next_state, next_transform);
00113 }
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123 void MultitexReducer::
00124 set_target(TextureStage *stage) {
00125 _target_stage = stage;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 void MultitexReducer::
00155 set_use_geom(bool use_geom) {
00156 _use_geom = use_geom;
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 void MultitexReducer::
00179 set_allow_tex_mat(bool allow_tex_mat) {
00180 _allow_tex_mat = allow_tex_mat;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 void MultitexReducer::
00195 flatten(GraphicsOutput *window) {
00196 if (grutil_cat.is_debug()) {
00197 grutil_cat.debug()
00198 << "Beginning flatten operation\n";
00199 Stages::const_iterator mi;
00200 for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
00201 const StageList &stage_list = (*mi).first;
00202 const GeomList &geom_list = (*mi).second;
00203 grutil_cat.debug(false)
00204 << "stage_list for:";
00205 for (GeomList::const_iterator gi = geom_list.begin();
00206 gi != geom_list.end();
00207 ++gi) {
00208 const GeomInfo &geom_info = (*gi);
00209 grutil_cat.debug(false)
00210 << " (" << geom_info._geom_node->get_name() << " g"
00211 << geom_info._index << ")";
00212 }
00213 grutil_cat.debug(false) << ":\n";
00214
00215 StageList::const_iterator si;
00216 for (si = stage_list.begin(); si != stage_list.end(); ++si) {
00217 const StageInfo &stage_info = (*si);
00218 grutil_cat.debug(false)
00219 << " " << *stage_info._stage << " " << *stage_info._tex
00220 << " " << *stage_info._tex_mat << "\n";
00221 }
00222 }
00223 }
00224 Stages::const_iterator mi;
00225 for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
00226 const StageList &stage_list = (*mi).first;
00227 const GeomList &geom_list = (*mi).second;
00228
00229
00230 bool use_transparent_bg = false;
00231 if(stage_list.size() > 0) {
00232 if(stage_list[0]._stage->get_mode() == TextureStage::M_decal)
00233 use_transparent_bg = true;
00234 else
00235 use_transparent_bg = false;
00236 }
00237 grutil_cat.debug(false) << "use transparent bg = " << use_transparent_bg << "\n";
00238
00239
00240
00241
00242
00243
00244
00245 const StageInfo &model_stage = stage_list[choose_model_stage(stage_list)];
00246
00247 Texture *model_tex = model_stage._tex;
00248 int aniso_degree = model_tex->get_anisotropic_degree();
00249 Texture::FilterType minfilter = model_tex->get_minfilter();
00250 Texture::FilterType magfilter = model_tex->get_magfilter();
00251
00252
00253 LTexCoord min_uv, max_uv;
00254 determine_uv_range(min_uv, max_uv, model_stage, geom_list);
00255
00256
00257
00258 LVecBase2 uv_scale;
00259 LVecBase2 uv_trans;
00260 get_uv_scale(uv_scale, uv_trans, min_uv, max_uv);
00261
00262
00263
00264
00265
00266
00267 int x_size;
00268 int y_size;
00269 choose_texture_size(x_size, y_size, model_stage, uv_scale,
00270 window);
00271
00272 static int multitex_id = 1;
00273 ostringstream multitex_name_strm;
00274 multitex_name_strm << "multitex" << multitex_id;
00275 multitex_id++;
00276
00277 GraphicsOutput *buffer = window->make_texture_buffer
00278 (multitex_name_strm.str(), x_size, y_size, NULL, false);
00279
00280
00281
00282 buffer->set_one_shot(true);
00283
00284 Texture *tex = buffer->get_texture();
00285 tex->set_anisotropic_degree(aniso_degree);
00286 tex->set_minfilter(minfilter);
00287 tex->set_magfilter(magfilter);
00288
00289
00290
00291 DisplayRegion *dr = buffer->make_display_region();
00292 PT(Camera) cam_node = new Camera("multitexCam");
00293 PT(Lens) lens = new OrthographicLens();
00294 lens->set_film_size(1.0f, 1.0f);
00295 lens->set_film_offset(0.5f, 0.5f);
00296 lens->set_near_far(-1000.0f, 1000.0f);
00297 lens->set_view_mat(LMatrix4(uv_scale[0], 0.0f, 0.0, 0.0f,
00298 0.0f, 1.0f, 0.0, 0.0f,
00299 0.0f, 0.0f, uv_scale[1], 0.0f,
00300 uv_trans[0], 0.0f, uv_trans[1], 1.0f));
00301 cam_node->set_lens(lens);
00302
00303
00304
00305 NodePath render("buffer");
00306 render.set_bin("unsorted", 0);
00307 render.set_depth_test(false);
00308 render.set_depth_write(false);
00309 render.set_two_sided(1);
00310
00311 NodePath cam = render.attach_new_node(cam_node);
00312 dr->set_camera(cam);
00313
00314
00315
00316
00317 bool force_use_geom = _use_geom;
00318 bool bake_in_color = _use_geom;
00319 LColor geom_color(1.0f, 1.0f, 1.0f, 1.0f);
00320
00321
00322 if(use_transparent_bg)
00323 geom_color = LColor(0.0f,0.0f,0.0f,0.0f);
00324
00325 if (!force_use_geom) {
00326 bool uses_decal = scan_decal(stage_list);
00327 if (uses_decal) {
00328
00329
00330 bake_in_color = true;
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 }
00342 }
00343
00344 if (!force_use_geom) {
00345
00346
00347
00348 CardMaker cm("background");
00349 cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]);
00350 if (bake_in_color) {
00351 cm.set_color(geom_color);
00352 }
00353 render.attach_new_node(cm.generate());
00354
00355 } else {
00356
00357
00358 nassertv(bake_in_color);
00359 PT(GeomNode) geom_node = new GeomNode("background");
00360 transfer_geom(geom_node, NULL, geom_list, true);
00361
00362 render.attach_new_node(geom_node);
00363 }
00364
00365 StageList::const_iterator si;
00366 for (si = stage_list.begin(); si != stage_list.end(); ++si) {
00367 const StageInfo &stage_info = (*si);
00368
00369 make_texture_layer(render, stage_info, geom_list,
00370 min_uv, max_uv, force_use_geom, use_transparent_bg);
00371 }
00372
00373
00374
00375 CPT(RenderAttrib) new_ta = DCAST(TextureAttrib, TextureAttrib::make())->
00376 add_on_stage(_target_stage, tex);
00377
00378 GeomList::const_iterator gi;
00379 for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
00380 const GeomInfo &geom_info = (*gi);
00381
00382 CPT(RenderState) geom_state =
00383 geom_info._geom_node->get_geom_state(geom_info._index);
00384 int override = geom_info._geom_net_state->get_override(TextureAttrib::get_class_slot());
00385 geom_state = geom_state->add_attrib(new_ta, override);
00386
00387 if (bake_in_color) {
00388
00389
00390 geom_state = geom_state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)));
00391
00392
00393
00394
00395
00396 const RenderAttrib *attrib =
00397 geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
00398
00399 if (attrib != (const RenderAttrib *)NULL) {
00400 geom_state = geom_state->add_attrib
00401 (attrib->invert_compose(ColorScaleAttrib::make_identity()));
00402 }
00403 }
00404
00405
00406 CPT(TransformState) tex_mat = TransformState::make_identity();
00407
00408 const RenderAttrib *ra = geom_info._state->get_attrib(TexMatrixAttrib::get_class_slot());
00409 if (ra != (const RenderAttrib *)NULL) {
00410
00411
00412 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, ra);
00413 CPT(TransformState) tex_mat = tma->get_transform(_target_stage);
00414 }
00415
00416 tex_mat = tex_mat->compose(TransformState::make_pos_hpr_scale
00417 (LVecBase3(uv_trans[0], uv_trans[1], 0.0f),
00418 LVecBase3(0.0f, 0.0f, 0.0f),
00419 LVecBase3(uv_scale[0], uv_scale[1], 1.0f)));
00420
00421 if (tex_mat->is_identity()) {
00422
00423 geom_state = geom_state->remove_attrib(TexMatrixAttrib::get_class_slot());
00424 } else {
00425
00426 CPT(RenderAttrib) new_tma = TexMatrixAttrib::make
00427 (_target_stage, tex_mat->invert_compose(TransformState::make_identity()));
00428 geom_state = geom_state->add_attrib(new_tma);
00429 }
00430
00431
00432 geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
00433 }
00434 }
00435
00436
00437
00438 GeomTransformer transformer;
00439
00440 GeomNodeList::const_iterator gni;
00441 for (gni = _geom_node_list.begin(); gni != _geom_node_list.end(); ++gni) {
00442 const GeomNodeInfo &geom_node_info = (*gni);
00443 AccumulatedAttribs attribs;
00444 attribs._texture =
00445 geom_node_info._state->get_attrib(TextureAttrib::get_class_slot());
00446 geom_node_info._geom_node->apply_attribs_to_vertices
00447 (attribs, SceneGraphReducer::TT_tex_matrix, transformer);
00448 }
00449 }
00450
00451
00452
00453
00454
00455
00456
00457 void MultitexReducer::
00458 scan_geom_node(GeomNode *node, const RenderState *state,
00459 const TransformState *transform) {
00460 if (grutil_cat.is_debug()) {
00461 grutil_cat.debug()
00462 << "scan_geom_node(" << *node << ", " << *state << ", "
00463 << *transform << ")\n";
00464 }
00465
00466 _geom_node_list.push_back(GeomNodeInfo(state, node));
00467
00468 int num_geoms = node->get_num_geoms();
00469 for (int gi = 0; gi < num_geoms; gi++) {
00470 CPT(RenderState) geom_net_state =
00471 state->compose(node->get_geom_state(gi));
00472
00473 if (grutil_cat.is_debug()) {
00474 grutil_cat.debug()
00475 << "geom " << gi << " net_state =\n";
00476 geom_net_state->write(cerr, 2);
00477 }
00478
00479
00480 const RenderAttrib *attrib;
00481 const TextureAttrib *ta = NULL;
00482
00483 attrib = geom_net_state->get_attrib(TextureAttrib::get_class_slot());
00484 if (attrib != (const RenderAttrib *)NULL) {
00485 ta = DCAST(TextureAttrib, attrib);
00486 }
00487
00488 if (ta == (TextureAttrib *)NULL) {
00489
00490 CPT(RenderState) geom_state = node->get_geom_state(gi);
00491 geom_state = geom_state->remove_attrib(TextureAttrib::get_class_slot());
00492 node->set_geom_state(gi, geom_state);
00493
00494 } else if (ta->get_num_on_stages() < 2) {
00495
00496
00497
00498 int override = geom_net_state->get_override(TextureAttrib::get_class_slot());
00499 CPT(RenderState) geom_state = node->get_geom_state(gi);
00500 geom_state = geom_state->add_attrib(ta, override);
00501 node->set_geom_state(gi, geom_state);
00502
00503 } else {
00504
00505 CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
00506 attrib = geom_net_state->get_attrib(TexMatrixAttrib::get_class_slot());
00507 if (attrib != (const RenderAttrib *)NULL) {
00508 tma = DCAST(TexMatrixAttrib, attrib);
00509 }
00510
00511 StageList stage_list;
00512
00513 int num_stages = ta->get_num_on_stages();
00514 for (int si = 0; si < num_stages; si++) {
00515 TextureStage *stage = ta->get_on_stage(si);
00516 Texture *tex = ta->get_on_texture(stage);
00517 if (tex->get_x_size() != 0 && tex->get_y_size() != 0) {
00518 stage_list.push_back(StageInfo(stage, ta, tma));
00519
00520 } else {
00521 grutil_cat.info()
00522 << "Ignoring invalid texture stage " << stage->get_name() << "\n";
00523 }
00524 }
00525
00526 if (stage_list.size() >= 2) {
00527 record_stage_list(stage_list, GeomInfo(state, geom_net_state, node, gi));
00528 }
00529 }
00530 }
00531 }
00532
00533
00534
00535
00536
00537
00538
00539 void MultitexReducer::
00540 record_stage_list(const MultitexReducer::StageList &stage_list,
00541 const MultitexReducer::GeomInfo &geom_info) {
00542 if (grutil_cat.is_debug()) {
00543 grutil_cat.debug()
00544 << "record_stage_list for " << geom_info._geom_node->get_name() << " g"
00545 << geom_info._index << ":\n";
00546 StageList::const_iterator si;
00547 for (si = stage_list.begin(); si != stage_list.end(); ++si) {
00548 const StageInfo &stage_info = (*si);
00549 grutil_cat.debug(false)
00550 << " " << *stage_info._stage << " " << *stage_info._tex
00551 << " " << *stage_info._tex_mat << "\n";
00552 }
00553 }
00554
00555 _stages[stage_list].push_back(geom_info);
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565 size_t MultitexReducer::
00566 choose_model_stage(const MultitexReducer::StageList &stage_list) const {
00567 for (size_t si = 0; si < stage_list.size(); si++) {
00568 const StageInfo &stage_info = stage_list[si];
00569 if (stage_info._stage == _target_stage) {
00570
00571 return si;
00572 }
00573 }
00574
00575
00576 return 0;
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586 bool MultitexReducer::
00587 determine_uv_range(LTexCoord &min_uv, LTexCoord &max_uv,
00588 const MultitexReducer::StageInfo &model_stage,
00589 const MultitexReducer::GeomList &geom_list) const {
00590 const InternalName *model_name = model_stage._stage->get_texcoord_name();
00591 bool got_any = false;
00592
00593 GeomList::const_iterator gi;
00594 for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
00595 const GeomInfo &geom_info = (*gi);
00596
00597 PT(Geom) geom =
00598 geom_info._geom_node->get_geom(geom_info._index)->make_copy();
00599
00600 CPT(GeomVertexData) vdata = geom->get_vertex_data();
00601 CPT(GeomVertexFormat) format = vdata->get_format();
00602 if (format->has_column(model_name)) {
00603 GeomVertexReader texcoord(vdata, model_name);
00604
00605 if (!texcoord.is_at_end()) {
00606 const LVecBase2 &uv = texcoord.get_data2();
00607 if (!got_any) {
00608 min_uv = max_uv = uv;
00609 got_any = true;
00610
00611 } else {
00612 min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
00613 max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
00614 }
00615
00616 while (!texcoord.is_at_end()) {
00617 const LVecBase2 &uv = texcoord.get_data2();
00618 min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
00619 max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
00620 }
00621 }
00622 }
00623 }
00624
00625 if (!got_any) {
00626 min_uv.set(0.0f, 0.0f);
00627 max_uv.set(1.0f, 1.0f);
00628 }
00629
00630 return got_any;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 void MultitexReducer::
00645 get_uv_scale(LVecBase2 &uv_scale, LVecBase2 &uv_trans,
00646 const LTexCoord &min_uv, const LTexCoord &max_uv) const {
00647 if (max_uv[0] != min_uv[0]) {
00648 uv_scale[0] = (max_uv[0] - min_uv[0]);
00649 } else {
00650 uv_scale[0] = 1.0f;
00651 }
00652
00653 if (max_uv[1] != min_uv[1]) {
00654 uv_scale[1] = (max_uv[1] - min_uv[1]);
00655 } else {
00656 uv_scale[1] = 1.0f;
00657 }
00658
00659 uv_trans[0] = (min_uv[0] + max_uv[0]) / 2.0f - uv_scale[0] * 0.5f;
00660 uv_trans[1] = (min_uv[1] + max_uv[1]) / 2.0f - uv_scale[1] * 0.5f;
00661 }
00662
00663
00664
00665
00666
00667
00668
00669
00670 void MultitexReducer::
00671 choose_texture_size(int &x_size, int &y_size,
00672 const MultitexReducer::StageInfo &model_stage,
00673 const LVecBase2 &uv_scale,
00674 GraphicsOutput *window) const {
00675 Texture *model_tex = model_stage._tex;
00676
00677
00678 x_size = model_tex->get_x_size();
00679 y_size = model_tex->get_y_size();
00680
00681
00682
00683
00684
00685
00686 LVecBase3 inherited_scale = model_stage._tex_mat->get_scale();
00687
00688 PN_stdfloat u_scale = cabs(inherited_scale[0]) * uv_scale[0];
00689 if (u_scale != 0.0f) {
00690 while (u_scale >= 2.0f) {
00691 x_size *= 2;
00692 u_scale *= 0.5f;
00693 }
00694 while (u_scale <= 0.5f && x_size > 0) {
00695 x_size /= 2;
00696 u_scale *= 2.0f;
00697 }
00698 }
00699
00700 PN_stdfloat v_scale = cabs(inherited_scale[1]) * uv_scale[1];
00701 if (v_scale != 0.0f) {
00702 while (v_scale >= 2.0f) {
00703 y_size *= 2;
00704 v_scale *= 0.5f;
00705 }
00706 while (v_scale <= 0.5f && y_size > 0) {
00707 y_size /= 2;
00708 v_scale *= 2.0f;
00709 }
00710 }
00711
00712 if (x_size == 0 || y_size == 0) {
00713 grutil_cat.warning()
00714 << "Texture size " << model_tex->get_x_size() << " "
00715 << model_tex->get_y_size() << " with scale "
00716 << model_stage._tex_mat->get_scale() << ", reduced to size "
00717 << x_size << " " << y_size << "; constraining to 1 1.\n";
00718 x_size = 1;
00719 y_size = 1;
00720 }
00721
00722
00723 if (max_texture_dimension > 0) {
00724 x_size = min(x_size, (int)max_texture_dimension);
00725 y_size = min(y_size, (int)max_texture_dimension);
00726 }
00727
00728
00729
00730 int win_x_size = window->get_x_size();
00731 if (win_x_size != 0 && x_size > win_x_size) {
00732 x_size /= 2;
00733 while (x_size > win_x_size) {
00734 x_size /= 2;
00735 }
00736 }
00737
00738 int win_y_size = window->get_y_size();
00739 if (win_y_size != 0 && y_size > win_y_size) {
00740 y_size /= 2;
00741 while (y_size > win_y_size) {
00742 y_size /= 2;
00743 }
00744 }
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754 void MultitexReducer::
00755 make_texture_layer(const NodePath &render,
00756 const MultitexReducer::StageInfo &stage_info,
00757 const MultitexReducer::GeomList &geom_list,
00758 const LTexCoord &min_uv, const LTexCoord &max_uv,
00759 bool force_use_geom, bool transparent_base) {
00760 CPT(RenderAttrib) cba;
00761
00762 switch (stage_info._stage->get_mode()) {
00763 case TextureStage::M_normal:
00764 case TextureStage::M_normal_height:
00765 case TextureStage::M_glow:
00766 case TextureStage::M_gloss:
00767 case TextureStage::M_height:
00768 case TextureStage::M_selector:
00769 case TextureStage::M_normal_gloss:
00770
00771
00772
00773
00774 case TextureStage::M_modulate_glow:
00775 case TextureStage::M_modulate_gloss:
00776 case TextureStage::M_modulate:
00777 cba = ColorBlendAttrib::make
00778 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
00779 ColorBlendAttrib::O_zero);
00780 break;
00781
00782 case TextureStage::M_decal:
00783 if(transparent_base) {
00784 cba = AlphaTestAttrib::make
00785 (AlphaTestAttrib::M_greater, 0.0f);
00786 } else {
00787 cba = ColorBlendAttrib::make
00788 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_incoming_alpha,
00789 ColorBlendAttrib::O_one_minus_incoming_alpha);
00790 }
00791 break;
00792
00793 case TextureStage::M_blend:
00794 cba = ColorBlendAttrib::make
00795 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
00796 ColorBlendAttrib::O_one_minus_incoming_color,
00797 stage_info._stage->get_color());
00798 break;
00799
00800 case TextureStage::M_replace:
00801 cba = ColorBlendAttrib::make_off();
00802 break;
00803
00804 case TextureStage::M_add:
00805 cba = ColorBlendAttrib::make
00806 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_one,
00807 ColorBlendAttrib::O_one);
00808 break;
00809
00810 case TextureStage::M_combine:
00811
00812 switch (stage_info._stage->get_combine_rgb_mode()) {
00813 case TextureStage::CM_modulate:
00814 {
00815 TextureStage::CombineSource source0 = stage_info._stage->get_combine_rgb_source0();
00816 TextureStage::CombineOperand operand0 = stage_info._stage->get_combine_rgb_operand0();
00817 TextureStage::CombineSource source1 = stage_info._stage->get_combine_rgb_source1();
00818 TextureStage::CombineOperand operand1 = stage_info._stage->get_combine_rgb_operand1();
00819
00820
00821
00822 if (source1 < source0) {
00823 source0 = stage_info._stage->get_combine_rgb_source1();
00824 operand0 = stage_info._stage->get_combine_rgb_operand1();
00825 source1 = stage_info._stage->get_combine_rgb_source0();
00826 operand1 = stage_info._stage->get_combine_rgb_operand0();
00827 }
00828
00829 if (source0 == TextureStage::CS_primary_color &&
00830 source1 == TextureStage::CS_previous) {
00831
00832
00833
00834 return;
00835
00836 } else if (source0 == TextureStage::CS_texture &&
00837 source1 == TextureStage::CS_constant) {
00838
00839 cba = ColorBlendAttrib::make
00840 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
00841 ColorBlendAttrib::O_zero, stage_info._stage->get_color());
00842
00843 } else if (source0 == TextureStage::CS_texture &&
00844 source1 == TextureStage::CS_previous) {
00845
00846 cba = ColorBlendAttrib::make
00847 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
00848 ColorBlendAttrib::O_zero);
00849
00850 } else {
00851
00852 return;
00853 }
00854 }
00855 break;
00856
00857 default:
00858
00859 return;
00860 }
00861 break;
00862
00863 case TextureStage::M_blend_color_scale:
00864
00865 cba = ColorBlendAttrib::make
00866 (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
00867 ColorBlendAttrib::O_one_minus_incoming_color,
00868 stage_info._stage->get_color());
00869 break;
00870 }
00871
00872 NodePath geom;
00873
00874 if (!force_use_geom && stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
00875
00876
00877 CardMaker cm(stage_info._tex->get_name());
00878 cm.set_uv_range(min_uv, max_uv);
00879 cm.set_has_uvs(true);
00880 cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]);
00881
00882 geom = render.attach_new_node(cm.generate());
00883
00884 } else {
00885
00886
00887
00888
00889
00890 PT(GeomNode) geom_node = new GeomNode(stage_info._tex->get_name());
00891 transfer_geom(geom_node, stage_info._stage->get_texcoord_name(),
00892 geom_list, false);
00893
00894 geom = render.attach_new_node(geom_node);
00895
00896 geom.set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
00897 }
00898
00899 if (!stage_info._tex_mat->is_identity()) {
00900 geom.set_tex_transform(TextureStage::get_default(), stage_info._tex_mat);
00901 }
00902
00903 geom.set_texture(stage_info._tex);
00904 geom.node()->set_attrib(cba);
00905 }
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916 void MultitexReducer::
00917 transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
00918 const MultitexReducer::GeomList &geom_list,
00919 bool preserve_color) {
00920 Thread *current_thread = Thread::get_current_thread();
00921 GeomList::const_iterator gi;
00922 for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
00923 const GeomInfo &geom_info = (*gi);
00924 const Geom *orig_geom = geom_info._geom_node->get_geom(geom_info._index);
00925
00926
00927
00928 PT(Geom) geom = orig_geom->make_copy();
00929
00930
00931 geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread));
00932
00933
00934
00935
00936 PT(GeomVertexData) vdata = geom->modify_vertex_data();
00937 vdata->set_usage_hint(Geom::UH_stream);
00938
00939 if (vdata->has_column(_target_stage->get_texcoord_name())) {
00940 GeomVertexWriter vertex(vdata, InternalName::get_vertex(), current_thread);
00941 GeomVertexReader texcoord(vdata, _target_stage->get_texcoord_name(), current_thread);
00942
00943 while (!texcoord.is_at_end()) {
00944 const LVecBase2 &tc = texcoord.get_data2();
00945 vertex.set_data3(tc[0], 0.0f, tc[1]);
00946 }
00947 }
00948
00949 if (texcoord_name != (const InternalName *)NULL &&
00950 texcoord_name != InternalName::get_texcoord()) {
00951
00952
00953 const GeomVertexColumn *column =
00954 vdata->get_format()->get_column(texcoord_name);
00955 if (column != (const GeomVertexColumn *)NULL) {
00956 vdata = vdata->replace_column
00957 (InternalName::get_texcoord(), column->get_num_components(),
00958 column->get_numeric_type(), column->get_contents());
00959 geom->set_vertex_data(vdata);
00960
00961 GeomVertexReader from(vdata, texcoord_name, current_thread);
00962 GeomVertexWriter to(vdata, InternalName::get_texcoord(), current_thread);
00963 while (!from.is_at_end()) {
00964 to.add_data2(from.get_data2());
00965 }
00966 }
00967 }
00968
00969 CPT(RenderState) geom_state = RenderState::make_empty();
00970 if (preserve_color) {
00971
00972 const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_slot());
00973 if (ca != (const RenderAttrib *)NULL) {
00974 geom_state = geom_state->add_attrib(ca);
00975 }
00976 const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
00977 if (csa != (const RenderAttrib *)NULL) {
00978 geom_state = geom_state->add_attrib(csa);
00979 }
00980 }
00981
00982 geom_node->add_geom(geom, geom_state);
00983 }
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999 void MultitexReducer::
01000 scan_color(const MultitexReducer::GeomList &geom_list, LColor &geom_color,
01001 int &num_colors) const {
01002 GeomList::const_iterator gi;
01003 for (gi = geom_list.begin(); gi != geom_list.end() && num_colors < 2; ++gi) {
01004 const GeomInfo &geom_info = (*gi);
01005
01006 LColor flat_color;
01007 bool has_flat_color = false;
01008 bool has_vertex_color = false;
01009
01010 LColor color_scale(1.0f, 1.0f, 1.0f, 1.0f);
01011 const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_slot());
01012 if (csa != (const RenderAttrib *)NULL) {
01013 const ColorScaleAttrib *a = DCAST(ColorScaleAttrib, csa);
01014 if (a->has_scale()) {
01015 color_scale = a->get_scale();
01016 }
01017 }
01018
01019 ColorAttrib::Type color_type = ColorAttrib::T_vertex;
01020 const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_slot());
01021 if (ca != (const RenderAttrib *)NULL) {
01022 color_type = DCAST(ColorAttrib, ca)->get_color_type();
01023 }
01024
01025 if (color_type == ColorAttrib::T_flat) {
01026
01027 flat_color = DCAST(ColorAttrib, ca)->get_color();
01028 has_flat_color = true;
01029
01030 } else if (color_type == ColorAttrib::T_vertex) {
01031
01032 const Geom *geom = geom_info._geom_node->get_geom(geom_info._index);
01033 if (geom->get_vertex_data()->has_column(InternalName::get_color())) {
01034
01035
01036 has_vertex_color = true;
01037 }
01038 }
01039
01040 if (has_vertex_color) {
01041 num_colors = 2;
01042
01043 } else if (has_flat_color) {
01044 flat_color.set(flat_color[0] * color_scale[0],
01045 flat_color[1] * color_scale[1],
01046 flat_color[2] * color_scale[2],
01047 flat_color[3] * color_scale[3]);
01048
01049 if (num_colors == 0) {
01050 num_colors = 1;
01051 geom_color = flat_color;
01052
01053 } else if (!flat_color.almost_equal(geom_color)) {
01054
01055 num_colors = 2;
01056 }
01057 }
01058 }
01059 }
01060
01061
01062
01063
01064
01065
01066
01067
01068 bool MultitexReducer::
01069 scan_decal(const MultitexReducer::StageList &stage_list) const {
01070 StageList::const_iterator si;
01071 for (si = stage_list.begin(); si != stage_list.end(); ++si) {
01072 const StageInfo &stage_info = (*si);
01073
01074 if (stage_info._stage->get_mode() == TextureStage::M_decal) {
01075 return true;
01076 }
01077 }
01078
01079 return false;
01080 }
01081
01082
01083
01084
01085
01086
01087
01088 MultitexReducer::StageInfo::
01089 StageInfo(TextureStage *stage, const TextureAttrib *ta,
01090 const TexMatrixAttrib *tma) :
01091 _stage(stage),
01092 _tex_mat(TransformState::make_identity())
01093 {
01094 _tex = ta->get_on_texture(_stage);
01095 if (tma->has_stage(stage)) {
01096 _tex_mat = tma->get_transform(stage);
01097 }
01098 }
01099