00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "eggRenderState.h"
00016 #include "eggRenderMode.h"
00017 #include "eggLine.h"
00018 #include "eggPoint.h"
00019 #include "textureAttrib.h"
00020 #include "renderAttrib.h"
00021 #include "eggTexture.h"
00022 #include "texGenAttrib.h"
00023 #include "internalName.h"
00024 #include "eggCurve.h"
00025 #include "eggSurface.h"
00026 #include "cullBinAttrib.h"
00027 #include "cullFaceAttrib.h"
00028 #include "shadeModelAttrib.h"
00029 #include "transparencyAttrib.h"
00030 #include "depthWriteAttrib.h"
00031 #include "depthTestAttrib.h"
00032 #include "depthOffsetAttrib.h"
00033 #include "texMatrixAttrib.h"
00034 #include "renderModeAttrib.h"
00035 #include "material.h"
00036 #include "materialAttrib.h"
00037 #include "materialPool.h"
00038 #include "config_gobj.h"
00039 #include "config_egg2pg.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048 void EggRenderState::
00049 fill_state(EggPrimitive *egg_prim) {
00050
00051
00052
00053
00054
00055 EggRenderMode::AlphaMode am = EggRenderMode::AM_unspecified;
00056 EggRenderMode::DepthWriteMode dwm = EggRenderMode::DWM_unspecified;
00057 EggRenderMode::DepthTestMode dtm = EggRenderMode::DTM_unspecified;
00058 EggRenderMode::VisibilityMode vm = EggRenderMode::VM_unspecified;
00059 bool implicit_alpha = false;
00060 bool binary_alpha_only = true;
00061 bool has_draw_order = false;
00062 int draw_order = 0;
00063 bool has_depth_offset = false;
00064 int depth_offset = 0;
00065 bool has_bin = false;
00066 string bin;
00067
00068 EggRenderMode *render_mode;
00069 render_mode = egg_prim->determine_alpha_mode();
00070 if (render_mode != (EggRenderMode *)NULL) {
00071 am = render_mode->get_alpha_mode();
00072 }
00073 render_mode = egg_prim->determine_depth_write_mode();
00074 if (render_mode != (EggRenderMode *)NULL) {
00075 dwm = render_mode->get_depth_write_mode();
00076 }
00077 render_mode = egg_prim->determine_depth_test_mode();
00078 if (render_mode != (EggRenderMode *)NULL) {
00079 dtm = render_mode->get_depth_test_mode();
00080 }
00081 render_mode = egg_prim->determine_visibility_mode();
00082 if (render_mode != (EggRenderMode *)NULL) {
00083 vm = render_mode->get_visibility_mode();
00084 }
00085 render_mode = egg_prim->determine_draw_order();
00086 if (render_mode != (EggRenderMode *)NULL) {
00087 has_draw_order = true;
00088 draw_order = render_mode->get_draw_order();
00089 }
00090 render_mode = egg_prim->determine_depth_offset();
00091 if (render_mode != (EggRenderMode *)NULL) {
00092 has_depth_offset = true;
00093 depth_offset = render_mode->get_depth_offset();
00094 }
00095 render_mode = egg_prim->determine_bin();
00096 if (render_mode != (EggRenderMode *)NULL) {
00097 has_bin = true;
00098 bin = render_mode->get_bin();
00099 }
00100
00101
00102 int num_textures = egg_prim->get_num_textures();
00103 CPT(RenderAttrib) texture_attrib = NULL;
00104 CPT(RenderAttrib) tex_gen_attrib = NULL;
00105 CPT(RenderAttrib) tex_mat_attrib = NULL;
00106 TexMats tex_mats;
00107
00108 for (int i = 0; i < num_textures; i++) {
00109 PT_EggTexture egg_tex = egg_prim->get_texture(i);
00110
00111 const TextureDef &def = _loader._textures[egg_tex];
00112 if (def._texture != (const RenderAttrib *)NULL) {
00113 if (texture_attrib == (RenderAttrib *)NULL) {
00114 texture_attrib = def._texture;
00115 } else {
00116 texture_attrib = texture_attrib->compose(def._texture);
00117 }
00118
00119 if (egg_tex->affects_polygon_alpha()) {
00120 const TextureAttrib *tex_attrib = DCAST(TextureAttrib, def._texture);
00121 Texture *tex = tex_attrib->get_texture();
00122 nassertv(tex != (Texture *)NULL);
00123
00124 Texture::Format format = tex->get_format();
00125 if (Texture::has_alpha(format) && !Texture::has_binary_alpha(format)) {
00126
00127 binary_alpha_only = false;
00128 }
00129
00130 if (am == EggRenderMode::AM_unspecified) {
00131
00132
00133
00134
00135 int num_components = tex->get_num_components();
00136 if (egg_tex->has_alpha_channel(num_components)) {
00137 implicit_alpha = true;
00138 }
00139 }
00140 }
00141
00142
00143 bool has_tex_gen = false;
00144 if (egg_tex->get_tex_gen() != EggTexture::TG_unspecified) {
00145 has_tex_gen = true;
00146 if (tex_gen_attrib == (const RenderAttrib *)NULL) {
00147 tex_gen_attrib = TexGenAttrib::make();
00148 }
00149 tex_gen_attrib = DCAST(TexGenAttrib, tex_gen_attrib)->
00150 add_stage(def._stage, get_tex_gen(egg_tex));
00151 }
00152
00153
00154
00155
00156
00157 CPT(InternalName) uv_name;
00158 if (egg_tex->has_uv_name() && egg_tex->get_uv_name() != string("default")) {
00159 uv_name = InternalName::get_texcoord_name(egg_tex->get_uv_name());
00160 } else {
00161 uv_name = InternalName::get_texcoord();
00162 }
00163
00164 if (has_tex_gen) {
00165
00166
00167
00168
00169 tex_mat_attrib = apply_tex_mat(tex_mat_attrib, def._stage, egg_tex);
00170
00171 } else {
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 tex_mats[uv_name][egg_tex->get_transform3d()].push_back(&def);
00183 }
00184 }
00185 }
00186
00187
00188
00189
00190
00191 bool needs_tex_mat = (egg_prim->is_of_type(EggCurve::get_class_type()) ||
00192 egg_prim->is_of_type(EggSurface::get_class_type()));
00193
00194
00195
00196
00197 TexMats::const_iterator tmi;
00198 for (tmi = tex_mats.begin(); tmi != tex_mats.end(); ++tmi) {
00199 const InternalName *uv_name = (*tmi).first;
00200 const TexMatTransforms &tmt = (*tmi).second;
00201
00202 if (tmt.size() == 1 && !needs_tex_mat) {
00203
00204
00205 const TexMatTextures &tmtex = (*tmt.begin()).second;
00206
00207
00208
00209 nassertv(!tmtex.empty());
00210 TexMatTextures::const_iterator tmtexi = tmtex.begin();
00211 const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
00212 if (egg_tex->has_transform()) {
00213
00214
00215
00216 _bake_in_uvs[uv_name] = egg_tex;
00217 }
00218
00219 } else {
00220
00221
00222
00223 TexMatTransforms::const_iterator tmti;
00224 for (tmti = tmt.begin(); tmti != tmt.end(); ++tmti) {
00225 const TexMatTextures &tmtex = (*tmti).second;
00226 TexMatTextures::const_iterator tmtexi;
00227 for (tmtexi = tmtex.begin(); tmtexi != tmtex.end(); ++tmtexi) {
00228 const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
00229 TextureStage *stage = (*tmtexi)->_stage;
00230
00231 tex_mat_attrib = apply_tex_mat(tex_mat_attrib, stage, egg_tex);
00232 }
00233 }
00234 }
00235 }
00236
00237 if (texture_attrib != (RenderAttrib *)NULL) {
00238 add_attrib(texture_attrib);
00239 }
00240
00241 if (tex_gen_attrib != (RenderAttrib *)NULL) {
00242 add_attrib(tex_gen_attrib);
00243 }
00244
00245 if (tex_mat_attrib != (RenderAttrib *)NULL) {
00246 add_attrib(tex_mat_attrib);
00247 }
00248
00249 if (egg_prim->has_material()) {
00250 PT(EggMaterial) material = egg_prim->get_material();
00251 CPT(RenderAttrib) mt =
00252 get_material_attrib(material, egg_prim->get_bface_flag());
00253 add_attrib(mt);
00254
00255 if (material->has_diff() && material->get_diff()[3] != 1.0) {
00256 implicit_alpha = true;
00257 binary_alpha_only = false;
00258 }
00259 }
00260
00261
00262
00263
00264 if (am == EggRenderMode::AM_unspecified) {
00265 if (egg_prim->has_color()) {
00266 if (egg_prim->get_color()[3] != 1.0) {
00267 implicit_alpha = true;
00268 binary_alpha_only = false;
00269 }
00270 }
00271 EggPrimitive::const_iterator vi;
00272 for (vi = egg_prim->begin();
00273 !implicit_alpha && vi != egg_prim->end();
00274 ++vi) {
00275 if ((*vi)->has_color()) {
00276 if ((*vi)->get_color()[3] != 1.0) {
00277 implicit_alpha = true;
00278 binary_alpha_only = false;
00279 }
00280 }
00281 }
00282
00283 if (implicit_alpha) {
00284 am = EggRenderMode::AM_on;
00285 }
00286 }
00287
00288 switch (am) {
00289 case EggRenderMode::AM_on:
00290
00291 if (binary_alpha_only) {
00292 am = EggRenderMode::AM_binary;
00293 } else if (egg_alpha_mode != EggRenderMode::AM_unspecified) {
00294 am = egg_alpha_mode;
00295 }
00296 break;
00297
00298 case EggRenderMode::AM_blend:
00299 case EggRenderMode::AM_ms:
00300 case EggRenderMode::AM_ms_mask:
00301 case EggRenderMode::AM_dual:
00302 if (egg_implicit_alpha_binary) {
00303
00304
00305
00306 if (binary_alpha_only) {
00307 am = EggRenderMode::AM_binary;
00308 }
00309 }
00310 break;
00311
00312 default:
00313 break;
00314 }
00315
00316 switch (am) {
00317 case EggRenderMode::AM_on:
00318 case EggRenderMode::AM_blend:
00319 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00320 break;
00321
00322 case EggRenderMode::AM_blend_no_occlude:
00323 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00324 add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
00325 break;
00326
00327 case EggRenderMode::AM_ms:
00328 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample));
00329 break;
00330
00331 case EggRenderMode::AM_ms_mask:
00332 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample_mask));
00333 break;
00334
00335 case EggRenderMode::AM_binary:
00336 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_binary));
00337 break;
00338
00339 case EggRenderMode::AM_dual:
00340 add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_dual));
00341 break;
00342
00343 default:
00344 break;
00345 }
00346
00347 switch (dwm) {
00348 case EggRenderMode::DWM_on:
00349 add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_on));
00350 break;
00351
00352 case EggRenderMode::DWM_off:
00353 add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
00354 break;
00355
00356 default:
00357 break;
00358 }
00359
00360 switch (dtm) {
00361 case EggRenderMode::DTM_on:
00362 add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_less));
00363 break;
00364
00365 case EggRenderMode::DTM_off:
00366 add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_none));
00367 break;
00368
00369 default:
00370 break;
00371 }
00372
00373 switch (vm) {
00374 case EggRenderMode::VM_hidden:
00375 _hidden = true;
00376 break;
00377
00378 case EggRenderMode::VM_normal:
00379 default:
00380 break;
00381 }
00382
00383 _flat_shaded =
00384 (egg_flat_shading &&
00385 egg_prim->get_connected_shading() == EggPrimitive::S_per_face);
00386
00387 if (_flat_shaded) {
00388 add_attrib(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
00389 }
00390
00391 if (egg_prim->is_of_type(EggLine::get_class_type())) {
00392 _primitive_type = Geom::PT_lines;
00393 EggLine *egg_line = DCAST(EggLine, egg_prim);
00394 if (egg_line->get_thick() != 1.0) {
00395 add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged,
00396 egg_line->get_thick()));
00397 }
00398 } else if (egg_prim->is_of_type(EggPoint::get_class_type())) {
00399 _primitive_type = Geom::PT_points;
00400 EggPoint *egg_point = DCAST(EggPoint, egg_prim);
00401 if (egg_point->get_thick() != 1.0 || egg_point->get_perspective()) {
00402 add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged,
00403 egg_point->get_thick(),
00404 egg_point->get_perspective()));
00405 }
00406 } else {
00407 _primitive_type = Geom::PT_polygons;
00408 }
00409
00410 if (has_bin) {
00411 add_attrib(CullBinAttrib::make(bin, draw_order));
00412
00413 } else if (has_draw_order) {
00414 add_attrib(CullBinAttrib::make("fixed", draw_order));
00415 }
00416 if (has_depth_offset) {
00417 add_attrib(DepthOffsetAttrib::make(depth_offset));
00418 }
00419
00420
00421 if (egg_prim->get_bface_flag()) {
00422
00423
00424 add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
00425 }
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435 int EggRenderState::
00436 compare_to(const EggRenderState &other) const {
00437 if (_state != other._state) {
00438 int c = _state->compare_to(*other._state);
00439 if (c != 0) {
00440 return c;
00441 }
00442 }
00443 if (_hidden != other._hidden) {
00444 return (int)_hidden - (int)other._hidden;
00445 }
00446 if (_flat_shaded != other._flat_shaded) {
00447 return (int)_flat_shaded - (int)other._flat_shaded;
00448 }
00449 if (_primitive_type != other._primitive_type) {
00450 return (int)_primitive_type - (int)other._primitive_type;
00451 }
00452
00453 if (_bake_in_uvs.size() != other._bake_in_uvs.size()) {
00454 return (int)_bake_in_uvs.size() - (int)other._bake_in_uvs.size();
00455 }
00456
00457 BakeInUVs::const_iterator ai, bi;
00458 ai = _bake_in_uvs.begin();
00459 bi = other._bake_in_uvs.begin();
00460 while (ai != _bake_in_uvs.end()) {
00461 nassertr(bi != other._bake_in_uvs.end(), false);
00462 if ((*ai).first != (*bi).first) {
00463 return (*ai).first < (*bi).first ? -1 : 1;
00464 }
00465 if ((*ai).second != (*bi).second) {
00466 return (*ai).second < (*bi).second ? -1 : 1;
00467 }
00468 ++ai;
00469 ++bi;
00470 }
00471 nassertr(bi == other._bake_in_uvs.end(), false);
00472
00473 return 0;
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483 CPT(RenderAttrib) EggRenderState::
00484 get_material_attrib(const EggMaterial *egg_mat, bool bface) {
00485 Materials &materials =
00486 bface ? _loader._materials_bface : _loader._materials;
00487
00488
00489 Materials::const_iterator mi;
00490 mi = materials.find(egg_mat);
00491 if (mi != materials.end()) {
00492 return (*mi).second;
00493 }
00494
00495
00496
00497 PT(Material) mat = new Material(egg_mat->get_name());
00498 if (egg_mat->has_diff()) {
00499 mat->set_diffuse(egg_mat->get_diff());
00500
00501
00502 mat->set_ambient(egg_mat->get_diff());
00503 }
00504 if (egg_mat->has_amb()) {
00505 mat->set_ambient(egg_mat->get_amb());
00506 }
00507 if (egg_mat->has_emit()) {
00508 mat->set_emission(egg_mat->get_emit());
00509 }
00510 if (egg_mat->has_spec()) {
00511 mat->set_specular(egg_mat->get_spec());
00512 }
00513 if (egg_mat->has_shininess()) {
00514 mat->set_shininess(egg_mat->get_shininess());
00515 }
00516 if (egg_mat->has_local()) {
00517 mat->set_local(egg_mat->get_local());
00518 }
00519
00520 mat->set_twoside(bface);
00521
00522
00523 Material *shared_mat = MaterialPool::get_material(mat);
00524
00525
00526 CPT(RenderAttrib) mt = MaterialAttrib::make(shared_mat);
00527 materials.insert(Materials::value_type(egg_mat, mt));
00528
00529 return mt;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 TexGenAttrib::Mode EggRenderState::
00539 get_tex_gen(const EggTexture *egg_tex) {
00540 switch (egg_tex->get_tex_gen()) {
00541 case EggTexture::TG_unspecified:
00542 return TexGenAttrib::M_off;
00543
00544 case EggTexture::TG_eye_sphere_map:
00545 return TexGenAttrib::M_eye_sphere_map;
00546
00547 case EggTexture::TG_world_cube_map:
00548 return TexGenAttrib::M_world_cube_map;
00549
00550 case EggTexture::TG_eye_cube_map:
00551 return TexGenAttrib::M_eye_cube_map;
00552
00553 case EggTexture::TG_world_normal:
00554 return TexGenAttrib::M_world_normal;
00555
00556 case EggTexture::TG_eye_normal:
00557 return TexGenAttrib::M_eye_normal;
00558
00559 case EggTexture::TG_world_position:
00560 return TexGenAttrib::M_world_position;
00561
00562 case EggTexture::TG_eye_position:
00563 return TexGenAttrib::M_eye_position;
00564
00565 case EggTexture::TG_point_sprite:
00566 return TexGenAttrib::M_point_sprite;
00567 };
00568
00569 return TexGenAttrib::M_off;
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 CPT(RenderAttrib) EggRenderState::
00580 apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib,
00581 TextureStage *stage, const EggTexture *egg_tex) {
00582 if (egg_tex->has_transform()) {
00583 CPT(TransformState) transform = _loader.make_transform(egg_tex);
00584
00585 if (tex_mat_attrib == (const RenderAttrib *)NULL) {
00586 tex_mat_attrib = TexMatrixAttrib::make();
00587 }
00588 tex_mat_attrib = DCAST(TexMatrixAttrib, tex_mat_attrib)->
00589 add_stage(stage, transform);
00590 }
00591
00592 return tex_mat_attrib;
00593 }