00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "textureReference.h"
00020 #include "textureImage.h"
00021 #include "paletteImage.h"
00022 #include "sourceTextureImage.h"
00023 #include "destTextureImage.h"
00024 #include "texturePlacement.h"
00025 #include "palettizer.h"
00026 #include "eggFile.h"
00027
00028 #include "indent.h"
00029 #include "eggTexture.h"
00030 #include "eggData.h"
00031 #include "eggGroupNode.h"
00032 #include "eggGroup.h"
00033 #include "eggNurbsSurface.h"
00034 #include "eggVertexPool.h"
00035 #include "datagram.h"
00036 #include "datagramIterator.h"
00037 #include "bamReader.h"
00038 #include "bamWriter.h"
00039 #include "string_utils.h"
00040
00041 #include <math.h>
00042
00043 TypeHandle TextureReference::_type_handle;
00044
00045
00046
00047
00048
00049
00050 TextureReference::
00051 TextureReference() {
00052 _egg_file = (EggFile *)NULL;
00053 _egg_tex = (EggTexture *)NULL;
00054 _tex_mat = LMatrix3d::ident_mat();
00055 _inv_tex_mat = LMatrix3d::ident_mat();
00056 _source_texture = (SourceTextureImage *)NULL;
00057 _placement = (TexturePlacement *)NULL;
00058 _uses_alpha = false;
00059 _any_uvs = false;
00060 _min_uv.set(0.0, 0.0);
00061 _max_uv.set(0.0, 0.0);
00062 _wrap_u = EggTexture::WM_unspecified;
00063 _wrap_v = EggTexture::WM_unspecified;
00064 }
00065
00066
00067
00068
00069
00070
00071 TextureReference::
00072 ~TextureReference() {
00073 clear_placement();
00074 }
00075
00076
00077
00078
00079
00080
00081
00082 void TextureReference::
00083 from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
00084 _egg_file = egg_file;
00085 _egg_tex = egg_tex;
00086 _egg_data = data;
00087
00088 if (_egg_tex->has_transform()) {
00089 _tex_mat = _egg_tex->get_transform();
00090 if (!_inv_tex_mat.invert_from(_tex_mat)) {
00091 _inv_tex_mat = LMatrix3d::ident_mat();
00092 }
00093 } else {
00094 _tex_mat = LMatrix3d::ident_mat();
00095 _inv_tex_mat = LMatrix3d::ident_mat();
00096 }
00097
00098 Filename filename = _egg_tex->get_filename();
00099 Filename alpha_filename;
00100 if (_egg_tex->has_alpha_filename()) {
00101 alpha_filename = _egg_tex->get_alpha_filename();
00102 }
00103 int alpha_file_channel = _egg_tex->get_alpha_file_channel();
00104
00105 _properties._format = _egg_tex->get_format();
00106 _properties._minfilter = _egg_tex->get_minfilter();
00107 _properties._magfilter = _egg_tex->get_magfilter();
00108 _properties._anisotropic_degree = _egg_tex->get_anisotropic_degree();
00109
00110 string name = filename.get_basename_wo_extension();
00111 TextureImage *texture = pal->get_texture(name);
00112 _source_texture = texture->get_source(filename, alpha_filename,
00113 alpha_file_channel);
00114 _source_texture->update_properties(_properties);
00115
00116 _uses_alpha = false;
00117 EggRenderMode::AlphaMode alpha_mode = _egg_tex->get_alpha_mode();
00118 if (alpha_mode == EggRenderMode::AM_unspecified) {
00119 if (_source_texture->get_size()) {
00120 _uses_alpha =
00121 _egg_tex->has_alpha_channel(_source_texture->get_num_channels());
00122 }
00123
00124 } else if (alpha_mode == EggRenderMode::AM_off) {
00125 _uses_alpha = false;
00126
00127 } else {
00128 _uses_alpha = true;
00129 }
00130
00131 get_uv_range(_egg_data, pal->_remap_uv);
00132
00133 _wrap_u = egg_tex->determine_wrap_u();
00134 _wrap_v = egg_tex->determine_wrap_v();
00135 }
00136
00137
00138
00139
00140
00141
00142 EggFile *TextureReference::
00143 get_egg_file() const {
00144 return _egg_file;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 SourceTextureImage *TextureReference::
00154 get_source() const {
00155 return _source_texture;
00156 }
00157
00158
00159
00160
00161
00162
00163 TextureImage *TextureReference::
00164 get_texture() const {
00165 nassertr(_source_texture != (SourceTextureImage *)NULL, (TextureImage *)NULL);
00166 return _source_texture->get_texture();
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 bool TextureReference::
00178 has_uvs() const {
00179 return _any_uvs;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 const TexCoordd &TextureReference::
00189 get_min_uv() const {
00190 nassertr(_any_uvs, _min_uv);
00191 return _min_uv;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200 const TexCoordd &TextureReference::
00201 get_max_uv() const {
00202 nassertr(_any_uvs, _max_uv);
00203 return _max_uv;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212 EggTexture::WrapMode TextureReference::
00213 get_wrap_u() const {
00214 return _wrap_u;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223 EggTexture::WrapMode TextureReference::
00224 get_wrap_v() const {
00225 return _wrap_v;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235 void TextureReference::
00236 set_placement(TexturePlacement *placement) {
00237 if (_placement != placement) {
00238 if (_placement != (TexturePlacement *)NULL) {
00239
00240 _placement->remove_egg(this);
00241 }
00242 _placement = placement;
00243 if (_placement != (TexturePlacement *)NULL) {
00244
00245 _placement->add_egg(this);
00246 }
00247 }
00248 }
00249
00250
00251
00252
00253
00254
00255 void TextureReference::
00256 clear_placement() {
00257 set_placement((TexturePlacement *)NULL);
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 TexturePlacement *TextureReference::
00269 get_placement() const {
00270 return _placement;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279 void TextureReference::
00280 mark_egg_stale() {
00281 if (_egg_file != (EggFile *)NULL) {
00282 _egg_file->mark_stale();
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293 void TextureReference::
00294 update_egg() {
00295 if (_egg_tex == (EggTexture *)NULL) {
00296
00297
00298 return;
00299 }
00300
00301 nassertv(_placement != (TexturePlacement *)NULL);
00302
00303
00304
00305 TextureImage *texture = get_texture();
00306 if (texture != (TextureImage *)NULL) {
00307 if (texture->has_num_channels() &&
00308 !_egg_tex->has_alpha_channel(texture->get_num_channels())) {
00309
00310
00311
00312 _egg_tex->set_alpha_mode(EggRenderMode::AM_unspecified);
00313
00314 } else {
00315
00316
00317 EggRenderMode::AlphaMode am = texture->get_alpha_mode();
00318 if (am != EggRenderMode::AM_unspecified) {
00319 _egg_tex->set_alpha_mode(am);
00320 }
00321 }
00322 }
00323
00324
00325
00326
00327 if (_placement->get_omit_reason() == OR_unknown) {
00328
00329
00330
00331
00332 Filename orig_filename = _egg_tex->get_filename();
00333 texture->update_egg_tex(_egg_tex);
00334 _egg_tex->set_filename(orig_filename.get_basename());
00335 return;
00336 }
00337 if (_placement->get_omit_reason() != OR_none) {
00338
00339
00340
00341 DestTextureImage *dest = _placement->get_dest();
00342 nassertv(dest != (DestTextureImage *)NULL);
00343 dest->update_egg_tex(_egg_tex);
00344 return;
00345 }
00346
00347
00348
00349
00350
00351 PaletteImage *image = _placement->get_image();
00352 nassertv(image != (PaletteImage *)NULL);
00353
00354 image->update_egg_tex(_egg_tex);
00355
00356 _egg_tex->set_wrap_mode(EggTexture::WM_clamp);
00357 _egg_tex->set_wrap_u(EggTexture::WM_unspecified);
00358 _egg_tex->set_wrap_v(EggTexture::WM_unspecified);
00359
00360 LMatrix3d new_tex_mat;
00361 _placement->compute_tex_matrix(new_tex_mat);
00362
00363
00364
00365 _egg_tex->set_transform(_tex_mat * new_tex_mat);
00366
00367
00368
00369 update_uv_range(_egg_data, pal->_remap_uv);
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 void TextureReference::
00381 apply_properties_to_source() {
00382 nassertv(_source_texture != (SourceTextureImage *)NULL);
00383 _source_texture->update_properties(_properties);
00384 }
00385
00386
00387
00388
00389
00390
00391 void TextureReference::
00392 output(ostream &out) const {
00393 out << *_source_texture;
00394 }
00395
00396
00397
00398
00399
00400
00401 void TextureReference::
00402 write(ostream &out, int indent_level) const {
00403 indent(out, indent_level)
00404 << get_texture()->get_name();
00405
00406 if (_uses_alpha) {
00407 out << " (uses alpha)";
00408 }
00409
00410 if (_any_uvs) {
00411
00412
00413 TexCoordd box = _max_uv - _min_uv;
00414 double area = box[0] * box[1];
00415
00416 out << " coverage " << area;
00417 }
00418
00419 if (_wrap_u != EggTexture::WM_unspecified ||
00420 _wrap_v != EggTexture::WM_unspecified) {
00421 if (_wrap_u != _wrap_v) {
00422 out << " (" << _wrap_u << ", " << _wrap_v << ")";
00423 } else {
00424 out << " " << _wrap_u;
00425 }
00426 }
00427
00428 if (_properties._format != EggTexture::F_unspecified) {
00429 out << " " << _properties._format;
00430 }
00431
00432 switch (_properties._minfilter) {
00433 case EggTexture::FT_nearest_mipmap_nearest:
00434 case EggTexture::FT_linear_mipmap_nearest:
00435 case EggTexture::FT_nearest_mipmap_linear:
00436 case EggTexture::FT_linear_mipmap_linear:
00437 out << " mipmap";
00438 break;
00439
00440 default:
00441 break;
00442 }
00443
00444 if(_properties._anisotropic_degree>1) {
00445 out << " aniso " << _properties._anisotropic_degree;
00446 }
00447
00448 out << "\n";
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 void TextureReference::
00471 get_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
00472 if (group->is_of_type(EggGroup::get_class_type())) {
00473 EggGroup *egg_group;
00474 DCAST_INTO_V(egg_group, group);
00475
00476 if (egg_group->get_dart_type() != EggGroup::DT_none) {
00477
00478
00479 remap = pal->_remap_char_uv;
00480 }
00481 }
00482
00483 bool group_any_uvs = false;
00484 TexCoordd group_min_uv, group_max_uv;
00485
00486 EggGroupNode::iterator ci;
00487 for (ci = group->begin(); ci != group->end(); ci++) {
00488 EggNode *child = (*ci);
00489 if (child->is_of_type(EggNurbsSurface::get_class_type())) {
00490 EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, child);
00491 if (nurbs->has_texture() && nurbs->get_texture() == _egg_tex) {
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 static const int num_nurbs_uvs = 4;
00506 static TexCoordd nurbs_uvs[num_nurbs_uvs] = {
00507 TexCoordd(0.0, 0.0),
00508 TexCoordd(0.0, 1.0),
00509 TexCoordd(1.0, 1.0),
00510 TexCoordd(1.0, 0.0)
00511 };
00512
00513 for (int i = 0; i < num_nurbs_uvs; i++) {
00514 TexCoordd uv = nurbs_uvs[i] * _tex_mat;
00515 collect_uv(_any_uvs, _min_uv, _max_uv, uv, uv);
00516 }
00517 }
00518
00519 } else if (child->is_of_type(EggPrimitive::get_class_type())) {
00520 EggPrimitive *geom = DCAST(EggPrimitive, child);
00521 if (geom->has_texture() && geom->get_texture() == _egg_tex) {
00522
00523
00524 TexCoordd geom_min_uv, geom_max_uv;
00525
00526 if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
00527 if (remap == Palettizer::RU_poly) {
00528 LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
00529 geom_min_uv += trans;
00530 geom_max_uv += trans;
00531 }
00532 collect_uv(group_any_uvs, group_min_uv, group_max_uv,
00533 geom_min_uv, geom_max_uv);
00534 }
00535 }
00536
00537 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00538 EggGroupNode *cg = DCAST(EggGroupNode, child);
00539 get_uv_range(cg, remap);
00540 }
00541 }
00542
00543 if (group_any_uvs) {
00544 if (remap == Palettizer::RU_group) {
00545 LVector2d trans = translate_uv(group_min_uv, group_max_uv);
00546 group_min_uv += trans;
00547 group_max_uv += trans;
00548 }
00549 collect_uv(_any_uvs, _min_uv, _max_uv, group_min_uv, group_max_uv);
00550 }
00551 }
00552
00553
00554
00555
00556
00557
00558
00559 void TextureReference::
00560 update_uv_range(EggGroupNode *group, Palettizer::RemapUV remap) {
00561 if (group->is_of_type(EggGroup::get_class_type())) {
00562 EggGroup *egg_group;
00563 DCAST_INTO_V(egg_group, group);
00564
00565 if (egg_group->get_dart_type() != EggGroup::DT_none) {
00566
00567
00568 remap = pal->_remap_char_uv;
00569 }
00570 }
00571
00572 bool group_any_uvs = false;
00573 TexCoordd group_min_uv, group_max_uv;
00574
00575 EggGroupNode::iterator ci;
00576 for (ci = group->begin(); ci != group->end(); ci++) {
00577 EggNode *child = (*ci);
00578 if (child->is_of_type(EggNurbsSurface::get_class_type())) {
00579
00580
00581
00582 } else if (child->is_of_type(EggPrimitive::get_class_type())) {
00583 if (remap != Palettizer::RU_never) {
00584 EggPrimitive *geom = DCAST(EggPrimitive, child);
00585 if (geom->has_texture() && geom->get_texture() == _egg_tex) {
00586 TexCoordd geom_min_uv, geom_max_uv;
00587
00588 if (get_geom_uvs(geom, geom_min_uv, geom_max_uv)) {
00589 if (remap == Palettizer::RU_poly) {
00590 LVector2d trans = translate_uv(geom_min_uv, geom_max_uv);
00591 trans = trans * _inv_tex_mat;
00592 if (!trans.almost_equal(LVector2d::zero())) {
00593 translate_geom_uvs(geom, trans);
00594 }
00595 } else {
00596 collect_uv(group_any_uvs, group_min_uv, group_max_uv,
00597 geom_min_uv, geom_max_uv);
00598 }
00599 }
00600 }
00601 }
00602
00603 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00604 EggGroupNode *cg = DCAST(EggGroupNode, child);
00605 update_uv_range(cg, remap);
00606 }
00607 }
00608
00609 if (group_any_uvs && remap == Palettizer::RU_group) {
00610 LVector2d trans = translate_uv(group_min_uv, group_max_uv);
00611 trans = trans * _inv_tex_mat;
00612 if (!trans.almost_equal(LVector2d::zero())) {
00613 for (ci = group->begin(); ci != group->end(); ci++) {
00614 EggNode *child = (*ci);
00615 if (child->is_of_type(EggPrimitive::get_class_type())) {
00616 EggPrimitive *geom = DCAST(EggPrimitive, child);
00617 if (geom->has_texture() && geom->get_texture() == _egg_tex) {
00618 translate_geom_uvs(geom, trans);
00619 }
00620 }
00621 }
00622 }
00623 }
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633 bool TextureReference::
00634 get_geom_uvs(EggPrimitive *geom,
00635 TexCoordd &geom_min_uv, TexCoordd &geom_max_uv) {
00636 bool geom_any_uvs = false;
00637
00638 EggPrimitive::iterator pi;
00639 for (pi = geom->begin(); pi != geom->end(); ++pi) {
00640 EggVertex *vtx = (*pi);
00641 if (vtx->has_uv()) {
00642 TexCoordd uv = vtx->get_uv() * _tex_mat;
00643 collect_uv(geom_any_uvs, geom_min_uv, geom_max_uv, uv, uv);
00644 }
00645 }
00646
00647 return geom_any_uvs;
00648 }
00649
00650
00651
00652
00653
00654
00655
00656 void TextureReference::
00657 translate_geom_uvs(EggPrimitive *geom, const TexCoordd &trans) const {
00658 EggPrimitive::iterator pi;
00659 for (pi = geom->begin(); pi != geom->end(); ++pi) {
00660 EggVertex *vtx = (*pi);
00661 if (vtx->has_uv()) {
00662 EggVertex vtx_copy(*vtx);
00663 vtx_copy.set_uv(vtx_copy.get_uv() + trans);
00664 EggVertex *new_vtx = vtx->get_pool()->create_unique_vertex(vtx_copy);
00665
00666 if (new_vtx->gref_size() != vtx->gref_size()) {
00667 new_vtx->copy_grefs_from(*vtx);
00668 }
00669
00670 geom->replace(pi, new_vtx);
00671 }
00672 }
00673 }
00674
00675
00676
00677
00678
00679
00680
00681 void TextureReference::
00682 collect_uv(bool &any_uvs, TexCoordd &min_uv, TexCoordd &max_uv,
00683 const TexCoordd &got_min_uv, const TexCoordd &got_max_uv) {
00684 if (any_uvs) {
00685 min_uv.set(min(min_uv[0], got_min_uv[0]),
00686 min(min_uv[1], got_min_uv[1]));
00687 max_uv.set(max(max_uv[0], got_max_uv[0]),
00688 max(max_uv[1], got_max_uv[1]));
00689 } else {
00690
00691 min_uv = got_min_uv;
00692 max_uv = got_max_uv;
00693 any_uvs = true;
00694 }
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704 LVector2d TextureReference::
00705 translate_uv(const TexCoordd &min_uv, const TexCoordd &max_uv) {
00706 TexCoordd center = (min_uv + max_uv) / 2;
00707 return LVector2d(-floor(center[0]), -floor(center[1]));
00708 }
00709
00710
00711
00712
00713
00714
00715
00716 void TextureReference::
00717 register_with_read_factory() {
00718 BamReader::get_factory()->
00719 register_factory(get_class_type(), make_TextureReference);
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729 void TextureReference::
00730 write_datagram(BamWriter *writer, Datagram &datagram) {
00731 TypedWritable::write_datagram(writer, datagram);
00732 writer->write_pointer(datagram, _egg_file);
00733
00734
00735
00736
00737 _tex_mat.write_datagram(datagram);
00738 _inv_tex_mat.write_datagram(datagram);
00739
00740 writer->write_pointer(datagram, _source_texture);
00741 writer->write_pointer(datagram, _placement);
00742
00743 datagram.add_bool(_uses_alpha);
00744 datagram.add_bool(_any_uvs);
00745 datagram.add_float64(_min_uv[0]);
00746 datagram.add_float64(_min_uv[1]);
00747 datagram.add_float64(_max_uv[0]);
00748 datagram.add_float64(_max_uv[1]);
00749 datagram.add_int32((int)_wrap_u);
00750 datagram.add_int32((int)_wrap_v);
00751 _properties.write_datagram(writer, datagram);
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763 int TextureReference::
00764 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00765 int pi = TypedWritable::complete_pointers(p_list, manager);
00766
00767 if (p_list[pi] != (TypedWritable *)NULL) {
00768 DCAST_INTO_R(_egg_file, p_list[pi], pi);
00769 }
00770 pi++;
00771
00772 if (p_list[pi] != (TypedWritable *)NULL) {
00773 DCAST_INTO_R(_source_texture, p_list[pi], pi);
00774 }
00775 pi++;
00776
00777 if (p_list[pi] != (TypedWritable *)NULL) {
00778 DCAST_INTO_R(_placement, p_list[pi], pi);
00779 }
00780 pi++;
00781
00782 pi += _properties.complete_pointers(p_list + pi, manager);
00783
00784 return pi;
00785 }
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795 TypedWritable* TextureReference::
00796 make_TextureReference(const FactoryParams ¶ms) {
00797 TextureReference *me = new TextureReference;
00798 DatagramIterator scan;
00799 BamReader *manager;
00800
00801 parse_params(params, scan, manager);
00802 me->fillin(scan, manager);
00803 return me;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 void TextureReference::
00814 fillin(DatagramIterator &scan, BamReader *manager) {
00815 TypedWritable::fillin(scan, manager);
00816 manager->read_pointer(scan);
00817
00818 _tex_mat.read_datagram(scan);
00819 _inv_tex_mat.read_datagram(scan);
00820
00821 manager->read_pointer(scan);
00822 manager->read_pointer(scan);
00823
00824 _uses_alpha = scan.get_bool();
00825 _any_uvs = scan.get_bool();
00826 _min_uv[0] = scan.get_float64();
00827 _min_uv[1] = scan.get_float64();
00828 _max_uv[0] = scan.get_float64();
00829 _max_uv[1] = scan.get_float64();
00830 _wrap_u = (EggTexture::WrapMode)scan.get_int32();
00831 _wrap_v = (EggTexture::WrapMode)scan.get_int32();
00832 _properties.fillin(scan, manager);
00833 }