00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "texturePlacement.h"
00016 #include "textureReference.h"
00017 #include "textureImage.h"
00018 #include "paletteGroup.h"
00019 #include "paletteImage.h"
00020 #include "palettizer.h"
00021 #include "eggFile.h"
00022 #include "destTextureImage.h"
00023
00024 #include "indent.h"
00025 #include "datagram.h"
00026 #include "datagramIterator.h"
00027 #include "bamReader.h"
00028 #include "bamWriter.h"
00029 #include "pnmImage.h"
00030
00031 TypeHandle TexturePlacement::_type_handle;
00032
00033
00034
00035
00036
00037
00038
00039 TexturePlacement::
00040 TexturePlacement() {
00041 _texture = (TextureImage *)NULL;
00042 _group = (PaletteGroup *)NULL;
00043 _image = (PaletteImage *)NULL;
00044 _dest = (DestTextureImage *)NULL;
00045 _has_uvs = false;
00046 _size_known = false;
00047 _is_filled = true;
00048 _omit_reason = OR_none;
00049 }
00050
00051
00052
00053
00054
00055
00056 TexturePlacement::
00057 TexturePlacement(TextureImage *texture, PaletteGroup *group) :
00058 _texture(texture),
00059 _group(group)
00060 {
00061 _omit_reason = OR_working;
00062
00063 if (!texture->is_size_known()) {
00064
00065
00066 _omit_reason = OR_unknown;
00067 }
00068
00069 _image = (PaletteImage *)NULL;
00070 _dest = (DestTextureImage *)NULL;
00071 _has_uvs = false;
00072 _size_known = false;
00073 _is_filled = false;
00074 }
00075
00076
00077
00078
00079
00080
00081 TexturePlacement::
00082 ~TexturePlacement() {
00083
00084
00085 References::iterator ri;
00086 References copy_references = _references;
00087 for (ri = copy_references.begin(); ri != copy_references.end(); ++ri) {
00088 TextureReference *reference = (*ri);
00089 nassertv(reference->get_placement() == this);
00090 reference->clear_placement();
00091 }
00092
00093
00094 _group->unplace(this);
00095 }
00096
00097
00098
00099
00100
00101
00102
00103 const string &TexturePlacement::
00104 get_name() const {
00105 return _texture->get_name();
00106 }
00107
00108
00109
00110
00111
00112
00113 TextureImage *TexturePlacement::
00114 get_texture() const {
00115 return _texture;
00116 }
00117
00118
00119
00120
00121
00122
00123 const TextureProperties &TexturePlacement::
00124 get_properties() const {
00125 return _texture->get_properties();
00126 }
00127
00128
00129
00130
00131
00132
00133 PaletteGroup *TexturePlacement::
00134 get_group() const {
00135 return _group;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 void TexturePlacement::
00145 add_egg(TextureReference *reference) {
00146 reference->mark_egg_stale();
00147
00148
00149
00150
00151
00152
00153
00154 _references.insert(reference);
00155 }
00156
00157
00158
00159
00160
00161
00162
00163 void TexturePlacement::
00164 remove_egg(TextureReference *reference) {
00165 reference->mark_egg_stale();
00166
00167
00168
00169
00170 _references.erase(reference);
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 void TexturePlacement::
00181 mark_eggs_stale() {
00182 References::iterator ri;
00183 for (ri = _references.begin(); ri != _references.end(); ++ri) {
00184 TextureReference *reference = (*ri);
00185
00186 reference->mark_egg_stale();
00187 }
00188 }
00189
00190
00191
00192
00193
00194
00195
00196 void TexturePlacement::
00197 set_dest(DestTextureImage *dest) {
00198 _dest = dest;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207 DestTextureImage *TexturePlacement::
00208 get_dest() const {
00209 return _dest;
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 bool TexturePlacement::
00226 determine_size() {
00227 if (!_texture->is_size_known()) {
00228
00229 force_replace();
00230 _omit_reason = OR_unknown;
00231 return false;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 _has_uvs = false;
00249 _position._wrap_u = EggTexture::WM_clamp;
00250 _position._wrap_v = EggTexture::WM_clamp;
00251
00252 LTexCoordd max_uv, min_uv;
00253
00254 References::iterator ri;
00255 for (ri = _references.begin(); ri != _references.end(); ++ri) {
00256 TextureReference *reference = (*ri);
00257 if (reference->has_uvs()) {
00258 const LTexCoordd &n = reference->get_min_uv();
00259 const LTexCoordd &x = reference->get_max_uv();
00260
00261 if (_has_uvs) {
00262 min_uv.set(min(min_uv[0], n[0]), min(min_uv[1], n[1]));
00263 max_uv.set(max(max_uv[0], x[0]), max(max_uv[1], x[1]));
00264 } else {
00265 min_uv = n;
00266 max_uv = x;
00267 _has_uvs = true;
00268 }
00269 }
00270
00271
00272
00273 if (reference->get_wrap_u() == EggTexture::WM_repeat) {
00274 _position._wrap_u = EggTexture::WM_repeat;
00275 }
00276 if (reference->get_wrap_v() == EggTexture::WM_repeat) {
00277 _position._wrap_v = EggTexture::WM_repeat;
00278 }
00279 }
00280
00281
00282
00283 if (_texture->get_txa_wrap_u() != EggTexture::WM_unspecified) {
00284 _position._wrap_u = _texture->get_txa_wrap_u();
00285 }
00286 if (_texture->get_txa_wrap_v() != EggTexture::WM_unspecified) {
00287 _position._wrap_v = _texture->get_txa_wrap_v();
00288 }
00289
00290 if (!_has_uvs) {
00291 force_replace();
00292 _omit_reason = OR_unused;
00293 return false;
00294 }
00295
00296 LTexCoordd rounded_min_uv = min_uv;
00297 LTexCoordd rounded_max_uv = max_uv;
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 if (pal->_round_uvs) {
00308 rounded_max_uv[0] =
00309 ceil((rounded_max_uv[0] - pal->_round_fuzz) / pal->_round_unit) *
00310 pal->_round_unit;
00311 rounded_max_uv[1] =
00312 ceil((rounded_max_uv[1] - pal->_round_fuzz) / pal->_round_unit) *
00313 pal->_round_unit;
00314
00315 rounded_min_uv[0] =
00316 floor((rounded_min_uv[0] + pal->_round_fuzz) / pal->_round_unit) *
00317 pal->_round_unit;
00318 rounded_min_uv[1] =
00319 floor((rounded_min_uv[1] + pal->_round_fuzz) / pal->_round_unit) *
00320 pal->_round_unit;
00321
00322
00323
00324 }
00325
00326
00327
00328 compute_size_from_uvs(rounded_min_uv, rounded_max_uv);
00329
00330
00331 if (_texture->get_omit()) {
00332
00333 force_replace();
00334 _omit_reason = OR_omitted;
00335
00336 } else if (get_uv_area() > _texture->get_coverage_threshold()) {
00337
00338 force_replace();
00339 _omit_reason = OR_coverage;
00340
00341 } else if ((_position._x_size > pal->_pal_x_size ||
00342 _position._y_size > pal->_pal_y_size) ||
00343 (_position._x_size == pal->_pal_x_size &&
00344 _position._y_size == pal->_pal_y_size)) {
00345
00346
00347
00348
00349 force_replace();
00350 _omit_reason = OR_size;
00351
00352 } else if (pal->_omit_everything && (_group->is_none_texture_swap())) {
00353
00354 force_replace();
00355 _omit_reason = OR_default_omit;
00356
00357 } else if (_omit_reason == OR_omitted ||
00358 _omit_reason == OR_default_omit ||
00359 _omit_reason == OR_size ||
00360 _omit_reason == OR_coverage ||
00361 _omit_reason == OR_unknown) {
00362
00363
00364
00365 force_replace();
00366 mark_eggs_stale();
00367 _omit_reason = OR_working;
00368
00369 } else if (is_placed()) {
00370
00371
00372
00373 if (_position._x_size != _placed._x_size ||
00374 _position._y_size != _placed._y_size ||
00375 _position._min_uv[0] < _placed._min_uv[0] ||
00376 _position._min_uv[1] < _placed._min_uv[1] ||
00377 _position._max_uv[0] > _placed._max_uv[0] ||
00378 _position._max_uv[1] > _placed._max_uv[1]) {
00379
00380
00381
00382
00383
00384
00385
00386 if ((_position._x_size > _placed._x_size ||
00387 _position._y_size > _placed._y_size) &&
00388 pal->_round_uvs) {
00389 compute_size_from_uvs(min_uv, max_uv);
00390 if (_position._x_size <= _placed._x_size &&
00391 _position._y_size <= _placed._y_size &&
00392 _position._min_uv[0] >= _placed._min_uv[0] &&
00393 _position._min_uv[1] >= _placed._min_uv[1] &&
00394 _position._max_uv[0] <= _placed._max_uv[0] &&
00395 _position._max_uv[1] <= _placed._max_uv[1]) {
00396
00397 } else {
00398
00399 compute_size_from_uvs(rounded_min_uv, rounded_max_uv);
00400 force_replace();
00401 }
00402 } else {
00403 force_replace();
00404 }
00405 }
00406
00407 if (_position._wrap_u != _placed._wrap_u ||
00408 _position._wrap_v != _placed._wrap_v) {
00409
00410
00411 _is_filled = false;
00412 _placed._wrap_u = _position._wrap_u;
00413 _placed._wrap_v = _position._wrap_v;
00414 }
00415 }
00416
00417 return true;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 bool TexturePlacement::
00431 is_size_known() const {
00432 return _size_known;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 OmitReason TexturePlacement::
00442 get_omit_reason() const {
00443 return _omit_reason;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 int TexturePlacement::
00455 get_x_size() const {
00456 nassertr(_size_known, 0);
00457 return _position._x_size;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 int TexturePlacement::
00469 get_y_size() const {
00470 nassertr(_size_known, 0);
00471 return _position._y_size;
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 double TexturePlacement::
00483 get_uv_area() const {
00484 if (!_has_uvs) {
00485 return 0.0;
00486 }
00487
00488 LTexCoordd range = _position._max_uv - _position._min_uv;
00489 return range[0] * range[1];
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 bool TexturePlacement::
00501 is_placed() const {
00502 return _image != (PaletteImage *)NULL;
00503 }
00504
00505
00506
00507
00508
00509
00510
00511 PaletteImage *TexturePlacement::
00512 get_image() const {
00513 nassertr(is_placed(), (PaletteImage *)NULL);
00514 return _image;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523 PalettePage *TexturePlacement::
00524 get_page() const {
00525 nassertr(is_placed(), (PalettePage *)NULL);
00526 return _image->get_page();
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536 int TexturePlacement::
00537 get_placed_x() const {
00538 nassertr(is_placed(), 0);
00539 return _placed._x;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549 int TexturePlacement::
00550 get_placed_y() const {
00551 nassertr(is_placed(), 0);
00552 return _placed._y;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562 int TexturePlacement::
00563 get_placed_x_size() const {
00564 nassertr(is_placed(), 0);
00565 return _placed._x_size;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575 int TexturePlacement::
00576 get_placed_y_size() const {
00577 nassertr(is_placed(), 0);
00578 return _placed._y_size;
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588 double TexturePlacement::
00589 get_placed_uv_area() const {
00590 nassertr(is_placed(), 0);
00591 LTexCoordd range = _placed._max_uv - _placed._min_uv;
00592 return range[0] * range[1];
00593 }
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 void TexturePlacement::
00604 place_at(PaletteImage *image, int x, int y) {
00605 nassertv(!is_placed());
00606 nassertv(_size_known);
00607
00608 _image = image;
00609 _is_filled = false;
00610 _position._x = x;
00611 _position._y = y;
00612 _placed = _position;
00613 _omit_reason = OR_none;
00614 }
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 void TexturePlacement::
00625 force_replace() {
00626 if (_image != (PaletteImage *)NULL) {
00627 _image->unplace(this);
00628 _image = (PaletteImage *)NULL;
00629 }
00630 if (_omit_reason == OR_none) {
00631 mark_eggs_stale();
00632 }
00633 _omit_reason = OR_working;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 void TexturePlacement::
00647 omit_solitary() {
00648 nassertv(is_placed());
00649 if (_omit_reason != OR_solitary) {
00650 mark_eggs_stale();
00651 _omit_reason = OR_solitary;
00652 }
00653 }
00654
00655
00656
00657
00658
00659
00660
00661 void TexturePlacement::
00662 not_solitary() {
00663 nassertv(is_placed());
00664 if (_omit_reason != OR_none) {
00665 mark_eggs_stale();
00666 _omit_reason = OR_none;
00667 }
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 bool TexturePlacement::
00679 intersects(int x, int y, int x_size, int y_size) {
00680 nassertr(is_placed(), false);
00681
00682 int hright = x + x_size;
00683 int hbot = y + y_size;
00684
00685 int mright = _placed._x + _placed._x_size;
00686 int mbot = _placed._y + _placed._y_size;
00687
00688 return !(x >= mright || hright <= _placed._x ||
00689 y >= mbot || hbot <= _placed._y);
00690 }
00691
00692
00693
00694
00695
00696
00697
00698
00699 void TexturePlacement::
00700 compute_tex_matrix(LMatrix3d &transform) {
00701 nassertv(is_placed());
00702
00703 LMatrix3d source_uvs = LMatrix3d::ident_mat();
00704
00705 LTexCoordd range = _placed._max_uv - _placed._min_uv;
00706 if (range[0] != 0.0 && range[1] != 0.0) {
00707 source_uvs =
00708 LMatrix3d::translate_mat(-_placed._min_uv) *
00709 LMatrix3d::scale_mat(1.0 / range[0], 1.0 / range[1]);
00710 }
00711
00712 int top = _placed._y + _placed._margin;
00713 int left = _placed._x + _placed._margin;
00714 int x_size = _placed._x_size - _placed._margin * 2;
00715 int y_size = _placed._y_size - _placed._margin * 2;
00716
00717 int bottom = top + y_size;
00718 int pal_x_size = _image->get_x_size();
00719 int pal_y_size = _image->get_y_size();
00720
00721 LVecBase2d t((double)left / (double)pal_x_size,
00722 (double)(pal_y_size - bottom) / (double)pal_y_size);
00723 LVecBase2d s((double)x_size / (double)pal_x_size,
00724 (double)y_size / (double)pal_y_size);
00725
00726 LMatrix3d dest_uvs
00727 (s[0], 0.0, 0.0,
00728 0.0, s[1], 0.0,
00729 t[0], t[1], 1.0);
00730
00731 transform = source_uvs * dest_uvs;
00732 }
00733
00734
00735
00736
00737
00738
00739
00740 void TexturePlacement::
00741 write_placed(ostream &out, int indent_level) {
00742 indent(out, indent_level)
00743 << get_texture()->get_name();
00744
00745 if (is_placed()) {
00746 out << " at "
00747 << get_placed_x() << " " << get_placed_y() << " to "
00748 << get_placed_x() + get_placed_x_size() << " "
00749 << get_placed_y() + get_placed_y_size() << " (coverage "
00750 << get_placed_uv_area() << ")";
00751
00752 if (_placed._wrap_u != EggTexture::WM_unspecified ||
00753 _placed._wrap_v != EggTexture::WM_unspecified) {
00754 if (_placed._wrap_u != _placed._wrap_v) {
00755 out << " (" << _placed._wrap_u << ", " << _placed._wrap_v << ")";
00756 } else {
00757 out << " " << _placed._wrap_u;
00758 }
00759 }
00760 out << "\n";
00761 } else {
00762 out << " not yet placed.\n";
00763 }
00764 };
00765
00766
00767
00768
00769
00770
00771
00772
00773 bool TexturePlacement::
00774 is_filled() const {
00775 return _is_filled;
00776 }
00777
00778
00779
00780
00781
00782
00783
00784 void TexturePlacement::
00785 mark_unfilled() {
00786 _is_filled = false;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796 void TexturePlacement::
00797 fill_image(PNMImage &image) {
00798 nassertv(is_placed());
00799
00800 _is_filled = true;
00801
00802
00803
00804
00805
00806
00807
00808 LMatrix3d transform;
00809 compute_tex_matrix(transform);
00810 LTexCoordd ul = LTexCoordd(0.0, 1.0) * transform;
00811 LTexCoordd lr = LTexCoordd(1.0, 0.0) * transform;
00812
00813
00814 int pal_x_size = _image->get_x_size();
00815 int pal_y_size = _image->get_y_size();
00816
00817 int top = (int)floor((1.0 - ul[1]) * pal_y_size + 0.5);
00818 int left = (int)floor(ul[0] * pal_x_size + 0.5);
00819 int bottom = (int)floor((1.0 - lr[1]) * pal_y_size + 0.5);
00820 int right = (int)floor(lr[0] * pal_x_size + 0.5);
00821
00822
00823
00824
00825 int x_size = right - left;
00826 int y_size = bottom - top;
00827 nassertv(x_size >= 0 && y_size >= 0);
00828
00829
00830
00831 const PNMImage &source_full = _texture->read_source_image();
00832 if (!source_full.is_valid()) {
00833 flag_error_image(image);
00834 return;
00835 }
00836
00837 PNMImage source(x_size, y_size, source_full.get_num_channels(),
00838 source_full.get_maxval());
00839 source.quick_filter_from(source_full);
00840
00841 bool alpha = image.has_alpha();
00842 bool source_alpha = source.has_alpha();
00843
00844
00845
00846
00847
00848
00849
00850 for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
00851 int sy = y - top;
00852
00853 if (_placed._wrap_v == EggTexture::WM_clamp) {
00854
00855 sy = max(min(sy, y_size - 1), 0);
00856
00857 } else {
00858
00859 sy = (sy < 0) ? y_size - 1 - ((-sy - 1) % y_size) : sy % y_size;
00860 }
00861
00862 for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
00863 int sx = x - left;
00864
00865 if (_placed._wrap_u == EggTexture::WM_clamp) {
00866
00867 sx = max(min(sx, x_size - 1), 0);
00868
00869 } else {
00870
00871 sx = (sx < 0) ? x_size - 1 - ((-sx - 1) % x_size) : sx % x_size;
00872 }
00873
00874 image.set_xel(x, y, source.get_xel(sx, sy));
00875 if (alpha) {
00876 if (source_alpha) {
00877 image.set_alpha(x, y, source.get_alpha(sx, sy));
00878 } else {
00879 image.set_alpha(x, y, 1.0);
00880 }
00881 }
00882 }
00883 }
00884
00885 _texture->release_source_image();
00886 }
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896 void TexturePlacement::
00897 fill_swapped_image(PNMImage &image, int index) {
00898 nassertv(is_placed());
00899
00900 _is_filled = true;
00901
00902
00903
00904
00905
00906
00907
00908 LMatrix3d transform;
00909 compute_tex_matrix(transform);
00910 LTexCoordd ul = LTexCoordd(0.0, 1.0) * transform;
00911 LTexCoordd lr = LTexCoordd(1.0, 0.0) * transform;
00912
00913
00914 int pal_x_size = _image->get_x_size();
00915 int pal_y_size = _image->get_y_size();
00916
00917 int top = (int)floor((1.0 - ul[1]) * pal_y_size + 0.5);
00918 int left = (int)floor(ul[0] * pal_x_size + 0.5);
00919 int bottom = (int)floor((1.0 - lr[1]) * pal_y_size + 0.5);
00920 int right = (int)floor(lr[0] * pal_x_size + 0.5);
00921
00922
00923
00924
00925 int x_size = right - left;
00926 int y_size = bottom - top;
00927 nassertv(x_size >= 0 && y_size >= 0);
00928
00929
00930
00931 TextureSwaps::iterator tsi;
00932 tsi = _textureSwaps.begin() + index;
00933 TextureImage *swapTexture = (*tsi);
00934 const PNMImage &source_full = swapTexture->read_source_image();
00935 if (!source_full.is_valid()) {
00936 flag_error_image(image);
00937 return;
00938 }
00939
00940 PNMImage source(x_size, y_size, source_full.get_num_channels(),
00941 source_full.get_maxval());
00942 source.quick_filter_from(source_full);
00943
00944 bool alpha = image.has_alpha();
00945 bool source_alpha = source.has_alpha();
00946
00947
00948
00949
00950
00951
00952
00953 for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
00954 int sy = y - top;
00955
00956 if (_placed._wrap_v == EggTexture::WM_clamp) {
00957
00958 sy = max(min(sy, y_size - 1), 0);
00959
00960 } else {
00961
00962 sy = (sy < 0) ? y_size - 1 - ((-sy - 1) % y_size) : sy % y_size;
00963 }
00964
00965 for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
00966 int sx = x - left;
00967
00968 if (_placed._wrap_u == EggTexture::WM_clamp) {
00969
00970 sx = max(min(sx, x_size - 1), 0);
00971
00972 } else {
00973
00974 sx = (sx < 0) ? x_size - 1 - ((-sx - 1) % x_size) : sx % x_size;
00975 }
00976
00977 image.set_xel(x, y, source.get_xel(sx, sy));
00978 if (alpha) {
00979 if (source_alpha) {
00980 image.set_alpha(x, y, source.get_alpha(sx, sy));
00981 } else {
00982 image.set_alpha(x, y, 1.0);
00983 }
00984 }
00985 }
00986 }
00987
00988 swapTexture->release_source_image();
00989 }
00990
00991
00992
00993
00994
00995
00996
00997
00998 void TexturePlacement::
00999 flag_error_image(PNMImage &image) {
01000 nassertv(is_placed());
01001 for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
01002 for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
01003 image.set_xel_val(x, y, 1, 0, 0);
01004 }
01005 }
01006 if (image.has_alpha()) {
01007 for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
01008 for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
01009 image.set_alpha_val(x, y, 1);
01010 }
01011 }
01012 }
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023 void TexturePlacement::
01024 compute_size_from_uvs(const LTexCoordd &min_uv, const LTexCoordd &max_uv) {
01025 _position._min_uv = min_uv;
01026 _position._max_uv = max_uv;
01027
01028 LTexCoordd range = _position._max_uv - _position._min_uv;
01029
01030
01031
01032
01033
01034 _position._x_size = (int)floor(_texture->get_x_size() * range[0] + 0.5);
01035 _position._y_size = (int)floor(_texture->get_y_size() * range[1] + 0.5);
01036
01037
01038
01039
01040
01041
01042 _position._x_size = max(_position._x_size, 4);
01043 _position._y_size = max(_position._y_size, 4);
01044
01045 if(get_group()->has_margin_override()) {
01046 _position._margin = get_group()->get_margin_override();
01047 } else {
01048 _position._margin = _texture->get_margin();
01049 }
01050
01051
01052
01053
01054
01055
01056 if ((double)_position._margin / (double)_position._x_size > 0.10) {
01057 _position._x_size += _position._margin * 2;
01058 }
01059 if ((double)_position._margin / (double)_position._y_size > 0.10) {
01060 _position._y_size += _position._margin * 2;
01061 }
01062
01063 _size_known = true;
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 void TexturePlacement::
01075 register_with_read_factory() {
01076 BamReader::get_factory()->
01077 register_factory(get_class_type(), make_TexturePlacement);
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087 void TexturePlacement::
01088 write_datagram(BamWriter *writer, Datagram &datagram) {
01089 TypedWritable::write_datagram(writer, datagram);
01090 writer->write_pointer(datagram, _texture);
01091 writer->write_pointer(datagram, _group);
01092 writer->write_pointer(datagram, _image);
01093 writer->write_pointer(datagram, _dest);
01094
01095 datagram.add_bool(_has_uvs);
01096 datagram.add_bool(_size_known);
01097 _position.write_datagram(writer, datagram);
01098
01099 datagram.add_bool(_is_filled);
01100 _placed.write_datagram(writer, datagram);
01101 datagram.add_int32((int)_omit_reason);
01102
01103 datagram.add_int32(_references.size());
01104 References::const_iterator ri;
01105 for (ri = _references.begin(); ri != _references.end(); ++ri) {
01106 writer->write_pointer(datagram, (*ri));
01107 }
01108
01109 datagram.add_int32(_textureSwaps.size());
01110 TextureSwaps::const_iterator tsi;
01111 for (tsi = _textureSwaps.begin(); tsi != _textureSwaps.end(); ++tsi) {
01112 writer->write_pointer(datagram, (*tsi));
01113 }
01114
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126 int TexturePlacement::
01127 complete_pointers(TypedWritable **p_list, BamReader *manager) {
01128 int index = TypedWritable::complete_pointers(p_list, manager);
01129
01130 if (p_list[index] != (TypedWritable *)NULL) {
01131 DCAST_INTO_R(_texture, p_list[index], index);
01132 }
01133 index++;
01134
01135 if (p_list[index] != (TypedWritable *)NULL) {
01136 DCAST_INTO_R(_group, p_list[index], index);
01137 }
01138 index++;
01139
01140 if (p_list[index] != (TypedWritable *)NULL) {
01141 DCAST_INTO_R(_image, p_list[index], index);
01142 }
01143 index++;
01144
01145 if (p_list[index] != (TypedWritable *)NULL) {
01146 DCAST_INTO_R(_dest, p_list[index], index);
01147 }
01148 index++;
01149
01150 int i;
01151 for (i = 0; i < _num_references; i++) {
01152 TextureReference *reference;
01153 DCAST_INTO_R(reference, p_list[index], index);
01154 _references.insert(reference);
01155 index++;
01156 }
01157
01158 for (i = 0; i < _num_textureSwaps; i++) {
01159 TextureImage *swapTexture;
01160 DCAST_INTO_R(swapTexture, p_list[index], index);
01161 _textureSwaps.push_back(swapTexture);
01162 index++;
01163 }
01164
01165 return index;
01166 }
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 TypedWritable* TexturePlacement::
01177 make_TexturePlacement(const FactoryParams ¶ms) {
01178 TexturePlacement *me = new TexturePlacement;
01179 DatagramIterator scan;
01180 BamReader *manager;
01181
01182 parse_params(params, scan, manager);
01183 me->fillin(scan, manager);
01184 return me;
01185 }
01186
01187
01188
01189
01190
01191
01192
01193
01194 void TexturePlacement::
01195 fillin(DatagramIterator &scan, BamReader *manager) {
01196 TypedWritable::fillin(scan, manager);
01197
01198 manager->read_pointer(scan);
01199 manager->read_pointer(scan);
01200 manager->read_pointer(scan);
01201 manager->read_pointer(scan);
01202
01203 _has_uvs = scan.get_bool();
01204 _size_known = scan.get_bool();
01205 _position.fillin(scan, manager);
01206
01207 _is_filled = scan.get_bool();
01208 _placed.fillin(scan, manager);
01209 _omit_reason = (OmitReason)scan.get_int32();
01210
01211 _num_references = scan.get_int32();
01212 manager->read_pointers(scan, _num_references);
01213
01214 if (Palettizer::_read_pi_version >= 20) {
01215 _num_textureSwaps = scan.get_int32();
01216 } else {
01217 _num_textureSwaps = 0;
01218 }
01219 manager->read_pointers(scan, _num_textureSwaps);
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 bool SortPlacementBySize::
01231 operator ()(TexturePlacement *a, TexturePlacement *b) const {
01232 if (a->get_y_size() < b->get_y_size()) {
01233 return false;
01234
01235 } else if (b->get_y_size() < a->get_y_size()) {
01236 return true;
01237
01238 } else if (a->get_x_size() < b->get_x_size()) {
01239 return false;
01240
01241 } else if (b->get_x_size() < a->get_x_size()) {
01242 return true;
01243 } else if (a->get_name() < b->get_name()) {
01244
01245 return true;
01246 }
01247
01248 return false;
01249 }