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