00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "cLwoSurface.h"
00016 #include "cLwoSurfaceBlock.h"
00017 #include "cLwoClip.h"
00018 #include "lwoToEggConverter.h"
00019
00020 #include "lwoSurfaceColor.h"
00021 #include "lwoSurfaceParameter.h"
00022 #include "lwoSurfaceSmoothingAngle.h"
00023 #include "lwoSurfaceSidedness.h"
00024 #include "lwoSurfaceBlock.h"
00025 #include "eggPrimitive.h"
00026 #include "string_utils.h"
00027 #include "mathNumbers.h"
00028 #include "dcast.h"
00029
00030
00031
00032
00033
00034
00035
00036 CLwoSurface::
00037 CLwoSurface(LwoToEggConverter *converter, const LwoSurface *surface) :
00038 _converter(converter),
00039 _surface(surface)
00040 {
00041 _flags = 0;
00042 _rgb.set(1.0, 1.0, 1.0);
00043 _checked_material = false;
00044 _checked_texture = false;
00045 _map_uvs = NULL;
00046 _block = (CLwoSurfaceBlock *)NULL;
00047
00048
00049 int num_chunks = _surface->get_num_chunks();
00050 for (int i = 0; i < num_chunks; i++) {
00051 const IffChunk *chunk = _surface->get_chunk(i);
00052
00053 if (chunk->is_of_type(LwoSurfaceColor::get_class_type())) {
00054 const LwoSurfaceColor *color = DCAST(LwoSurfaceColor, chunk);
00055 _flags |= F_rgb;
00056 _rgb = color->_color;
00057
00058 } else if (chunk->is_of_type(LwoSurfaceParameter::get_class_type())) {
00059 const LwoSurfaceParameter *param = DCAST(LwoSurfaceParameter, chunk);
00060 IffId type = param->get_id();
00061
00062 if (type == IffId("DIFF")) {
00063 _flags |= F_diffuse;
00064 _diffuse = param->_value;
00065
00066 } else if (type == IffId("LUMI")) {
00067 _flags |= F_luminosity;
00068 _luminosity = param->_value;
00069
00070 } else if (type == IffId("SPEC")) {
00071 _flags |= F_specular;
00072 _specular = param->_value;
00073
00074 } else if (type == IffId("REFL")) {
00075 _flags |= F_reflection;
00076 _reflection = param->_value;
00077
00078 } else if (type == IffId("TRAN")) {
00079 _flags |= F_transparency;
00080 _transparency = param->_value;
00081
00082 } else if (type == IffId("GLOS")) {
00083 _flags |= F_gloss;
00084 _gloss = param->_value;
00085
00086 } else if (type == IffId("TRNL")) {
00087 _flags |= F_translucency;
00088 _translucency = param->_value;
00089 }
00090
00091 } else if (chunk->is_of_type(LwoSurfaceSmoothingAngle::get_class_type())) {
00092 const LwoSurfaceSmoothingAngle *sa = DCAST(LwoSurfaceSmoothingAngle, chunk);
00093 _flags |= F_smooth_angle;
00094 _smooth_angle = sa->_angle;
00095
00096 } else if (chunk->is_of_type(LwoSurfaceSidedness::get_class_type())) {
00097 const LwoSurfaceSidedness *sn = DCAST(LwoSurfaceSidedness, chunk);
00098 _flags |= F_backface;
00099 _backface = (sn->_sidedness == LwoSurfaceSidedness::S_front_and_back);
00100
00101 } else if (chunk->is_of_type(LwoSurfaceBlock::get_class_type())) {
00102 const LwoSurfaceBlock *lwo_block = DCAST(LwoSurfaceBlock, chunk);
00103
00104
00105
00106 CLwoSurfaceBlock *block = new CLwoSurfaceBlock(_converter, lwo_block);
00107
00108
00109 if (block->_block_type == IffId("IMAP") &&
00110 block->_channel_id == IffId("COLR") &&
00111 block->_enabled) {
00112
00113 if (_block == (CLwoSurfaceBlock *)NULL) {
00114 _block = block;
00115
00116 } else if (block->_ordinal < _block->_ordinal) {
00117 delete _block;
00118 _block = block;
00119
00120 } else {
00121 delete block;
00122 }
00123
00124 } else {
00125 delete block;
00126 }
00127 }
00128 }
00129
00130
00131
00132 _color.set(1.0, 1.0, 1.0, 1.0);
00133
00134 if ((_flags & F_rgb) != 0) {
00135 _color[0] = _rgb[0];
00136 _color[1] = _rgb[1];
00137 _color[2] = _rgb[2];
00138 }
00139
00140 if ((_flags & F_transparency) != 0) {
00141 _color[3] = 1.0 - _transparency;
00142 }
00143
00144 _diffuse_color = _color;
00145 }
00146
00147
00148
00149
00150
00151
00152 CLwoSurface::
00153 ~CLwoSurface() {
00154 if (_block != (CLwoSurfaceBlock *)NULL) {
00155 delete _block;
00156 }
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 void CLwoSurface::
00170 apply_properties(EggPrimitive *egg_prim, vector_PT_EggVertex &egg_vertices,
00171 PN_stdfloat &smooth_angle) {
00172 if (!_surface->_source.empty()) {
00173
00174
00175 CLwoSurface *parent = _converter->get_surface(_surface->_source);
00176 if (parent != (CLwoSurface *)NULL && parent != this) {
00177 parent->apply_properties(egg_prim, egg_vertices, smooth_angle);
00178 }
00179 }
00180
00181 bool has_texture = check_texture();
00182 bool has_material = check_material();
00183
00184 egg_prim->set_color(_diffuse_color);
00185
00186 if (has_material) {
00187 egg_prim->set_material(_egg_material);
00188 }
00189
00190 if (has_texture) {
00191 egg_prim->set_texture(_egg_texture);
00192
00193
00194 generate_uvs(egg_vertices);
00195 }
00196
00197 if ((_flags & F_backface) != 0) {
00198 egg_prim->set_bface_flag(_backface);
00199 }
00200
00201 if ((_flags & F_smooth_angle) != 0) {
00202 smooth_angle = max(smooth_angle, _smooth_angle);
00203 }
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 bool CLwoSurface::
00217 check_texture() {
00218 if (_checked_texture) {
00219 return (_egg_texture != (EggTexture *)NULL);
00220 }
00221 _checked_texture = true;
00222 _egg_texture = (EggTexture *)NULL;
00223 _map_uvs = NULL;
00224
00225 if (_block == (CLwoSurfaceBlock *)NULL) {
00226
00227 return false;
00228 }
00229
00230 int clip_index = _block->_clip_index;
00231 if (clip_index < 0) {
00232
00233 return false;
00234 }
00235
00236 CLwoClip *clip = _converter->get_clip(clip_index);
00237 if (clip == (CLwoClip *)NULL) {
00238 nout << "No clip image with index " << clip_index << "\n";
00239 return false;
00240 }
00241
00242 if (!clip->is_still_image()) {
00243
00244 return false;
00245 }
00246
00247 Filename pathname = _converter->convert_model_path(clip->_filename);
00248
00249 _egg_texture = new EggTexture("clip" + format_string(clip_index), pathname);
00250
00251
00252 switch (_block->_projection_mode) {
00253 case LwoSurfaceBlockProjection::M_planar:
00254 _map_uvs = &CLwoSurface::map_planar;
00255 break;
00256
00257 case LwoSurfaceBlockProjection::M_cylindrical:
00258 _map_uvs = &CLwoSurface::map_cylindrical;
00259 break;
00260
00261 case LwoSurfaceBlockProjection::M_spherical:
00262 _map_uvs = &CLwoSurface::map_spherical;
00263 break;
00264
00265 case LwoSurfaceBlockProjection::M_cubic:
00266 _map_uvs = &CLwoSurface::map_cubic;
00267 break;
00268
00269 case LwoSurfaceBlockProjection::M_front:
00270
00271
00272
00273 break;
00274
00275 case LwoSurfaceBlockProjection::M_uv:
00276
00277
00278
00279 break;
00280 };
00281
00282
00283 _color[0] = 1.0;
00284 _color[1] = 1.0;
00285 _color[2] = 1.0;
00286
00287 return true;
00288 }
00289
00290
00291
00292
00293
00294
00295
00296 bool CLwoSurface::
00297 check_material() {
00298 if (_checked_material) {
00299 return (_egg_material != (EggMaterial *)NULL);
00300 }
00301 _checked_material = true;
00302 _egg_material = (EggMaterial *)NULL;
00303
00304 if (!_converter->_make_materials) {
00305
00306 return false;
00307 }
00308
00309 _egg_material = new EggMaterial(get_name());
00310
00311 if ((_flags & F_diffuse) != 0) {
00312 _diffuse_color.set(_color[0] * _diffuse,
00313 _color[1] * _diffuse,
00314 _color[2] * _diffuse,
00315 _color[3]);
00316
00317
00318
00319
00320
00321
00322
00323 }
00324
00325 if ((_flags & F_luminosity) != 0) {
00326 LColor luminosity(_color[0] * _luminosity,
00327 _color[1] * _luminosity,
00328 _color[2] * _luminosity,
00329 1.0);
00330 _egg_material->set_emit(luminosity);
00331 }
00332
00333 if ((_flags & F_specular) != 0) {
00334 LColor specular(_color[0] * _specular,
00335 _color[1] * _specular,
00336 _color[2] * _specular,
00337 1.0);
00338 _egg_material->set_spec(specular);
00339 }
00340
00341 if ((_flags & F_gloss) != 0) {
00342 _egg_material->set_shininess(_gloss * 128.0);
00343 }
00344
00345 return true;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 void CLwoSurface::
00357 generate_uvs(vector_PT_EggVertex &egg_vertices) {
00358 if (_map_uvs == NULL) {
00359 return;
00360 }
00361
00362
00363
00364
00365 LPoint3d centroid(0.0, 0.0, 0.0);
00366
00367 vector_PT_EggVertex::const_iterator vi;
00368 for (vi = egg_vertices.begin(); vi != egg_vertices.end(); ++vi) {
00369 EggVertex *egg_vertex = (*vi);
00370 centroid += egg_vertex->get_pos3();
00371 }
00372
00373 centroid /= (double)egg_vertices.size();
00374 centroid = centroid * _block->_inv_transform;
00375
00376
00377 for (vi = egg_vertices.begin(); vi != egg_vertices.end(); ++vi) {
00378 EggVertex *egg_vertex = (*vi);
00379 LPoint3d pos = egg_vertex->get_pos3() * _block->_inv_transform;
00380 LPoint2d uv = (this->*_map_uvs)(pos, centroid);
00381 egg_vertex->set_uv(uv);
00382 }
00383 }
00384
00385
00386
00387
00388
00389
00390
00391 LPoint2d CLwoSurface::
00392 map_planar(const LPoint3d &pos, const LPoint3d &) const {
00393
00394
00395 double u = (pos[0] + 0.5);
00396 double v = (pos[2] + 0.5);
00397
00398 return LPoint2d(u, v);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 LPoint2d CLwoSurface::
00408 map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const {
00409
00410
00411
00412
00413 LVector2d xz_orig(pos[0], pos[2]);
00414 LVector2d xz = xz_orig;
00415 double u_offset = 0.0;
00416
00417 if (xz == LVector2d::zero()) {
00418
00419
00420
00421
00422
00423
00424
00425 xz.set(centroid[0], centroid[2]);
00426
00427 } else if (xz[1] >= 0.0 && ((xz[0] < 0.0) != (centroid[0] < 0.))) {
00428
00429
00430
00431
00432
00433
00434
00435 u_offset = (xz[0] < 0.0) ? 1.0 : -1.0;
00436 }
00437
00438
00439
00440 double u =
00441 (atan2(xz[0], -xz[1]) / (2.0 * MathNumbers::pi) + 0.5 + u_offset) * _block->_w_repeat;
00442
00443
00444
00445 LVector2d yz(pos[1], xz_orig.length());
00446 double v =
00447 (atan2(yz[0], yz[1]) / MathNumbers::pi + 0.5) * _block->_h_repeat;
00448
00449 return LPoint2d(u, v);
00450 }
00451
00452
00453
00454
00455
00456
00457
00458 LPoint2d CLwoSurface::
00459 map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const {
00460
00461
00462
00463 LVector2d xz(pos[0], pos[2]);
00464 double u_offset = 0.0;
00465
00466 if (xz == LVector2d::zero()) {
00467
00468
00469
00470
00471 xz.set(centroid[0], centroid[2]);
00472
00473 } else if (xz[1] >= 0.0 && ((xz[0] < 0.0) != (centroid[0] < 0.))) {
00474
00475 u_offset = (xz[0] < 0.0) ? 1.0 : -1.0;
00476 }
00477
00478 double u =
00479 (atan2(xz[0], -xz[1]) / (2.0 * MathNumbers::pi) + 0.5 + u_offset) * _block->_w_repeat;
00480
00481
00482
00483 double v = (pos[1] + 0.5);
00484
00485 return LPoint2d(u, v);
00486 }
00487
00488
00489
00490
00491
00492
00493
00494 LPoint2d CLwoSurface::
00495 map_cubic(const LPoint3d &pos, const LPoint3d ¢roid) const {
00496
00497
00498
00499
00500 double x = fabs(centroid[0]);
00501 double y = fabs(centroid[1]);
00502 double z = fabs(centroid[2]);
00503
00504 double u, v;
00505
00506 if (x > y) {
00507 if (x > z) {
00508
00509 u = (pos[2] + 0.5);
00510 v = (pos[1] + 0.5);
00511 } else {
00512
00513 u = (pos[0] + 0.5);
00514 v = (pos[1] + 0.5);
00515 }
00516 } else {
00517 if (y > z) {
00518
00519 u = (pos[0] + 0.5);
00520 v = (pos[2] + 0.5);
00521 } else {
00522
00523 u = (pos[0] + 0.5);
00524 v = (pos[1] + 0.5);
00525 }
00526 }
00527
00528 return LPoint2d(u, v);
00529 }