00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "chancfg.h"
00020 #include "notify.h"
00021 #include "displayRegion.h"
00022 #include "graphicsPipe.h"
00023 #include "graphicsEngine.h"
00024 #include "graphicsChannel.h"
00025 #include "hardwareChannel.h"
00026 #include "camera.h"
00027 #include "frustum.h"
00028 #include "perspectiveLens.h"
00029 #include "dSearchPath.h"
00030 #include "dconfig.h"
00031 #include "filename.h"
00032 #include "transformState.h"
00033 #include "dcast.h"
00034 #include "config_express.h"
00035 #include "virtualFileSystem.h"
00036
00037 #include <algorithm>
00038 #include <stdio.h>
00039
00040
00041 Configure(chanconfig);
00042
00043 ConfigureFn(chanconfig) {
00044 }
00045
00046 static bool have_read = false;
00047 NotifyCategoryDef(chancfg, "");
00048
00049 static bool
00050 load_chancfg_database(const string &filename, const DSearchPath &path,
00051 const string &type_desc, void (*parser_func)(istream &)) {
00052 Filename fname = Filename::text_filename(filename);
00053
00054 if (use_vfs) {
00055 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00056
00057 if (!vfs->resolve_filename(fname, path)) {
00058 chancfg_cat.error()
00059 << "Could not find " << type_desc << " database " << filename
00060 << " in path " << path << "\n";
00061 return false;
00062
00063 } else {
00064 istream *ifs;
00065 ifs = vfs->open_read_file(fname);
00066 if (ifs == (istream *)NULL) {
00067 chancfg_cat.error()
00068 << "Unable to read " << type_desc << " database "
00069 << filename << "\n";
00070 return false;
00071 }
00072 if (chancfg_cat.is_debug()) {
00073 chancfg_cat.debug()
00074 << "Reading " << type_desc << " database " << filename
00075 << "\n";
00076 }
00077 parser_func(*ifs);
00078 delete ifs;
00079 }
00080
00081 } else {
00082
00083 if (!fname.resolve_filename(path)) {
00084 chancfg_cat.error()
00085 << "Could not find " << type_desc << " database " << filename
00086 << " in path " << path << "\n";
00087 return false;
00088
00089 } else {
00090 ifstream ifs;
00091 if (!fname.open_read(ifs)) {
00092 chancfg_cat.error()
00093 << "Unable to read " << type_desc << " database "
00094 << filename << "\n";
00095 return false;
00096 }
00097 if (chancfg_cat.is_debug()) {
00098 chancfg_cat.debug()
00099 << "Reading " << type_desc << " database " << filename
00100 << "\n";
00101 }
00102 parser_func(ifs);
00103 }
00104 }
00105
00106 return true;
00107 }
00108
00109 static void ReadChanConfigData(void) {
00110 if (have_read)
00111 return;
00112
00113 ResetLayout();
00114 ResetSetup();
00115 ResetWindow();
00116
00117
00118
00119
00120
00121
00122
00123 DSearchPath orig_path(chanconfig.GetString("ETC_PATH", "."), " \n\t");
00124 DSearchPath path;
00125 for (int i = 0; i < orig_path.get_num_directories(); i++) {
00126 path.append_directory(Filename::from_os_specific(orig_path.get_directory(i)));
00127 }
00128
00129 string layoutdbfilename = chanconfig.GetString("layout-db-file","layout_db");
00130 string windowdbfilename = chanconfig.GetString("window-db-file","window_db");
00131 string setupdbfilename = chanconfig.GetString("setup-db-file","setup_db");
00132
00133 load_chancfg_database(layoutdbfilename, path, "layout", ParseLayout);
00134 load_chancfg_database(setupdbfilename, path, "setup", ParseSetup);
00135 load_chancfg_database(windowdbfilename, path, "window", ParseWindow);
00136 }
00137
00138 static const bool config_sanity_check =
00139 chanconfig.GetBool("chan-config-sanity-check", false);
00140
00141 ChanCfgOverrides ChanOverrideNone;
00142
00143 INLINE bool LayoutDefined(std::string sym) {
00144 return (LayoutDB != (LayoutType *)NULL) &&
00145 (LayoutDB->find(sym) != LayoutDB->end());
00146 }
00147
00148 INLINE bool SetupDefined(std::string sym) {
00149 return (SetupDB != (SetupType *)NULL) &&
00150 (SetupDB->find(sym) != SetupDB->end());
00151 }
00152
00153 INLINE bool ConfigDefined(std::string sym) {
00154 return (WindowDB != (WindowType *)NULL) &&
00155 (WindowDB->find(sym) != WindowDB->end());
00156 }
00157
00158 bool ChanCheckLayouts(SetupSyms& S) {
00159 if (S.empty())
00160 return false;
00161 for (SetupSyms::iterator i=S.begin(); i!=S.end(); ++i)
00162 if (!LayoutDefined(*i)) {
00163 chancfg_cat.error() << "no layout called '" << *i << "'" << endl;
00164 return false;
00165 }
00166 return true;
00167 }
00168
00169 bool ChanCheckSetups(SetupSyms& S) {
00170 if (S.empty())
00171 return false;
00172 for (SetupSyms::iterator i=S.begin(); i!=S.end(); ++i) {
00173 if (!SetupDefined(*i)) {
00174 chancfg_cat.error() << "no setup called '" << *i << "'" << endl;
00175 return false;
00176 }
00177 }
00178 return true;
00179 }
00180
00181 INLINE ChanViewport ChanScaleViewport(const ChanViewport& parent,
00182 const ChanViewport& child) {
00183 float dx = (parent.right() - parent.left());
00184 float dy = (parent.top() - parent.bottom());
00185 ChanViewport v(parent.left() + (dx * child.left()),
00186 parent.left() + (dx * child.right()),
00187 parent.bottom() + (dy * child.bottom()),
00188 parent.bottom() + (dy * child.top()));
00189 return v;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 SetupFOV ChanResolveFOV(SetupFOV& fov, float sizeX, float sizeY) {
00202 float horiz = 45.0f;
00203 float vert;
00204 SetupFOV ret;
00205 switch (fov.getType()) {
00206 case SetupFOV::Horizontal:
00207 horiz = fov.getHoriz();
00208 if (chancfg_cat.is_debug())
00209 chancfg_cat->debug() << "ChanResolveFOV:: setting default horiz = "
00210 << horiz << endl;
00211 case SetupFOV::Default:
00212 horiz = chanconfig.GetFloat("fov", horiz);
00213 vert = 2.0f*rad_2_deg(atan((sizeY/sizeX)*tan(0.5f*deg_2_rad(horiz))));
00214 if (chancfg_cat.is_debug())
00215 chancfg_cat->debug() << "ChanResolveFOV:: setting horiz = " << horiz
00216 << " and vert = " << vert << endl;
00217 break;
00218 case SetupFOV::Both:
00219 horiz = fov.getHoriz();
00220 vert = fov.getVert();
00221 if (chancfg_cat.is_debug())
00222 chancfg_cat->debug() << "ChanResolveFOV:: setting horiz = " << horiz
00223 << " and vert = " << vert << endl;
00224 break;
00225
00226 default:
00227 break;
00228 }
00229
00230 ret.setFOV(horiz, vert);
00231 return ret;
00232 }
00233
00234 void ChanConfig::chan_eval(GraphicsWindow* win, WindowItem& W, LayoutItem& L,
00235 SVec& S,
00236 ChanViewport& V, int hw_offset, int xsize, int ysize,
00237 const NodePath &render, bool want_cameras) {
00238 int i = min(L.GetNumRegions(), int(S.size()));
00239 int j;
00240 SVec::iterator k;
00241 std::vector< PT(PandaNode) >camera(W.getNumCameraGroups());
00242
00243 camera[0] = new PandaNode("camera");
00244 for(int icam=1;icam<W.getNumCameraGroups();icam++) {
00245 char dummy[10];
00246 sprintf(dummy,"%d",icam);
00247 std::string nodeName = "camera";
00248 nodeName.append(dummy);
00249 camera[icam] = new PandaNode(nodeName);
00250 }
00251 for (j=0, k=S.begin(); j<i; ++j, ++k) {
00252 ChanViewport v(ChanScaleViewport(V, L[j]));
00253 PT(GraphicsChannel) chan;
00254 if ((*k).getHWChan() && W.getHWChans()) {
00255 if ((*k).getChan() == -1) {
00256 chan = win->get_channel(hw_offset);
00257 } else
00258 chan = win->get_channel((*k).getChan());
00259
00260 v = ChanViewport(0.0f, 1.0f, 0.0f, 1.0f);
00261 } else {
00262 chan = win->get_channel(0);
00263 }
00264 ChanViewport v2(ChanScaleViewport(v, (*k).getViewport()));
00265 PT(GraphicsLayer) layer = chan->make_layer();
00266 PT(DisplayRegion) dr =
00267 layer->make_display_region(v2.left(), v2.right(),
00268 v2.bottom(), v2.top());
00269 if (want_cameras && camera[0] != (PandaNode *)NULL) {
00270
00271 PT(Camera) cam = new Camera("");
00272 dr->set_camera(NodePath(cam));
00273 _display_region.push_back(dr);
00274 SetupFOV fov = (*k).getFOV();
00275
00276
00277
00278
00279
00280
00281 float xConsoleSize = xsize*(v2.right()-v2.left());
00282 float yConsoleSize = ysize*(v2.top()-v2.bottom());
00283 float xDisplaySize, yDisplaySize;
00284 if ( (*k).getOrientation() == SetupItem::Left ||
00285 (*k).getOrientation() == SetupItem::Right ) {
00286 xDisplaySize = yConsoleSize;
00287 yDisplaySize = xConsoleSize;
00288 } else {
00289 xDisplaySize = xConsoleSize;
00290 yDisplaySize = yConsoleSize;
00291 }
00292 fov = ChanResolveFOV(fov, xDisplaySize, yDisplaySize);
00293 if (chancfg_cat->is_debug()) {
00294 chancfg_cat->debug() << "ChanEval:: FOVhoriz = " << fov.getHoriz()
00295 << " FOVvert = " << fov.getVert() << endl;
00296 chancfg_cat->debug() << "ChanEval:: xsize = " << xsize
00297 << " ysize = " << ysize << endl;
00298 }
00299
00300
00301 CPT(TransformState) orient;
00302 float hFov, vFov;
00303
00304 switch ((*k).getOrientation()) {
00305 case SetupItem::Up:
00306 hFov = fov.getHoriz(); vFov = fov.getVert();
00307 break;
00308 case SetupItem::Down:
00309 hFov = fov.getHoriz(); vFov = fov.getVert();
00310 orient = TransformState::make_mat
00311 (LMatrix4f::rotate_mat_normaxis(180.0f, LVector3f::forward()));
00312 break;
00313 case SetupItem::Left:
00314
00315 hFov = fov.getVert(); vFov = fov.getHoriz();
00316 orient = TransformState::make_mat
00317 (LMatrix4f::rotate_mat_normaxis(90.0f, LVector3f::forward()));
00318 break;
00319 case SetupItem::Right:
00320
00321 hFov = fov.getVert(); vFov = fov.getHoriz();
00322 orient = TransformState::make_mat
00323 (LMatrix4f::rotate_mat_normaxis(-90.0f, LVector3f::forward()));
00324 break;
00325 }
00326
00327 PT(Lens) lens = new PerspectiveLens;
00328 lens->set_fov(hFov, vFov);
00329 lens->set_near_far(1.0f, 10000.0f);
00330 cam->set_lens(lens);
00331
00332
00333
00334 if (chancfg_cat->is_debug())
00335 chancfg_cat->debug() << "ChanEval:: camera hfov = "
00336 << lens->get_hfov() << " vfov = "
00337 << lens->get_vfov() << endl;
00338 cam->set_scene(render);
00339
00340 camera[W.getCameraGroup(j)]->add_child(cam);
00341 if (orient != (TransformState *)NULL) {
00342 cam->set_transform(orient);
00343 }
00344 }
00345 }
00346 _group_node = camera;
00347 return;
00348 }
00349
00350 ChanConfig::ChanConfig(GraphicsEngine *engine, GraphicsPipe* pipe,
00351 std::string cfg, const NodePath &render,
00352 ChanCfgOverrides& overrides) {
00353 ReadChanConfigData();
00354
00355 if (!ConfigDefined(cfg)) {
00356 chancfg_cat.error()
00357 << "no window configuration called '" << cfg << "'" << endl;
00358 _graphics_window = (GraphicsWindow*)0;
00359 return;
00360 }
00361 WindowItem W = (*WindowDB)[cfg];
00362
00363 std::string l = W.getLayout();
00364 if (!LayoutDefined(l)) {
00365 chancfg_cat.error()
00366 << "No layout called '" << l << "'" << endl;
00367 _graphics_window = (GraphicsWindow*)0;
00368 return;
00369 }
00370 LayoutItem L = (*LayoutDB)[l];
00371
00372 SetupSyms s = W.getSetups();
00373 if (!ChanCheckSetups(s)) {
00374 chancfg_cat.error() << "Setup failure" << endl;
00375 _graphics_window = (GraphicsWindow*)0;
00376 return;
00377 }
00378
00379 SVec S;
00380 S.reserve(s.size());
00381 for (SetupSyms::iterator i=s.begin(); i!=s.end(); ++i)
00382 S.push_back((*SetupDB)[(*i)]);
00383
00384
00385 int sizeX = chanconfig.GetInt("win-width", -1);
00386 int sizeY = chanconfig.GetInt("win-height", -1);
00387 if (overrides.defined(ChanCfgOverrides::SizeX))
00388 sizeX = overrides.getInt(ChanCfgOverrides::SizeX);
00389 if (overrides.defined(ChanCfgOverrides::SizeY))
00390 sizeY = overrides.getInt(ChanCfgOverrides::SizeY);
00391 if (sizeX < 0) {
00392 if (sizeY < 0) {
00393 if(chancfg_cat.is_debug())
00394 chancfg_cat.debug() << "Using default chan-window size\n";
00395
00396 sizeX = W.getSizeX();
00397 sizeY = W.getSizeY();
00398 } else {
00399
00400
00401 sizeX = (W.getSizeX() * sizeY) / W.getSizeY();
00402 }
00403 } else if (sizeY < 0) {
00404
00405
00406 sizeY = (W.getSizeY() * sizeX) / W.getSizeX();
00407 }
00408
00409 int origX = chanconfig.GetInt("win-origin-x");
00410 int origY = chanconfig.GetInt("win-origin-y");
00411 origX = overrides.defined(ChanCfgOverrides::OrigX) ?
00412 overrides.getInt(ChanCfgOverrides::OrigX) : origX;
00413 origY = overrides.defined(ChanCfgOverrides::OrigY) ?
00414 overrides.getInt(ChanCfgOverrides::OrigY) : origY;
00415
00416 bool undecorated = chanconfig.GetBool("undecorated", !W.getBorder());
00417 bool fullscreen = chanconfig.GetBool("fullscreen", false);
00418 bool use_cursor = !chanconfig.GetBool("cursor-hidden", !W.getCursor());
00419 int want_depth_bits = chanconfig.GetInt("want-depth-bits", 1);
00420 int want_color_bits = chanconfig.GetInt("want-color-bits", 1);
00421
00422 float win_background_r = chanconfig.GetFloat("win-background-r", 0.41);
00423 float win_background_g = chanconfig.GetFloat("win-background-g", 0.41);
00424 float win_background_b = chanconfig.GetFloat("win-background-b", 0.41);
00425
00426
00427 int frame_buffer_mode =
00428 FrameBufferProperties::FM_rgba |
00429 FrameBufferProperties::FM_double_buffer |
00430 FrameBufferProperties::FM_depth;
00431 frame_buffer_mode = overrides.defined(ChanCfgOverrides::Mask) ?
00432 overrides.getUInt(ChanCfgOverrides::Mask) : frame_buffer_mode;
00433
00434 std::string title = cfg;
00435 title = overrides.defined(ChanCfgOverrides::Title) ?
00436 overrides.getString(ChanCfgOverrides::Title) : title;
00437
00438 FrameBufferProperties fbprops;
00439 fbprops.set_frame_buffer_mode(frame_buffer_mode);
00440 fbprops.set_depth_bits(want_depth_bits);
00441 fbprops.set_color_bits(want_color_bits);
00442
00443 WindowProperties props;
00444 props.set_open(true);
00445 props.set_origin(origX, origY);
00446 props.set_size(sizeX, sizeY);
00447 props.set_title(title);
00448 props.set_undecorated(undecorated);
00449 props.set_fullscreen(fullscreen);
00450 props.set_cursor_hidden(!use_cursor);
00451
00452
00453
00454
00455
00456 bool want_cameras = overrides.defined(ChanCfgOverrides::Cameras) ?
00457 overrides.getBool(ChanCfgOverrides::Cameras) : true;
00458
00459
00460 PT(GraphicsStateGuardian) gsg =
00461 engine->make_gsg(pipe, fbprops, engine->get_threading_model());
00462 PT(GraphicsWindow) win = engine->make_window(pipe, gsg);
00463 if(win == (GraphicsWindow *)NULL) {
00464 chancfg_cat.error() << "Could not create window" << endl;
00465 _graphics_window = (GraphicsWindow *)NULL;
00466 return;
00467 }
00468
00469 win->request_properties(props);
00470 win->set_clear_color(Colorf(win_background_r, win_background_g,
00471 win_background_b, 1.0f));
00472
00473
00474 ChanViewport V(0.0f, 1.0f, 0.0f, 1.0f);
00475 chan_eval(win, W, L, S, V, W.getChanOffset()+1, sizeX, sizeY,
00476 render, want_cameras);
00477 for(size_t dr_index=0; dr_index<_display_region.size(); dr_index++)
00478 _group_membership.push_back(W.getCameraGroup(dr_index));
00479
00480
00481 if (config_sanity_check) {
00482 nout << "ChanConfig Sanity check:" << endl
00483 << "window - " << (void*)win << endl;
00484
00485 int max_channel_index = win->get_max_channel_index();
00486 for (int c = 0; c < max_channel_index; c++) {
00487 if (win->is_channel_defined(c)) {
00488 GraphicsChannel *chan = win->get_channel(c);
00489 nout << " Chan - " << (void*)chan << endl
00490 << " window = " << (void*)(chan->get_window()) << endl
00491 << " active = " << chan->is_active() << endl;
00492
00493 int num_layers = chan->get_num_layers();
00494 for (int l = 0; l < num_layers; l++) {
00495 GraphicsLayer *layer = chan->get_layer(l);
00496 nout << " Layer - " << (void*)layer << endl
00497 << " channel = " << (void*)(layer->get_channel()) << endl
00498 << " active = " << layer->is_active() << endl;
00499
00500 int num_drs = layer->get_num_drs();
00501 for (int d = 0; d < num_drs; d++) {
00502 DisplayRegion *dr = layer->get_dr(d);
00503 nout << " DR - " << (void*)dr << endl
00504 << " layer = " << (void*)(dr->get_layer()) << endl;
00505 float ll, rr, bb, tt;
00506 dr->get_dimensions(ll, rr, bb, tt);
00507 nout << " (" << ll << " " << rr << " " << bb << " " << tt << ")" << endl
00508 << " camera = " << dr->get_camera() << endl;
00509 NodePath cmm = dr->get_camera();
00510 if (!cmm.is_empty()) {
00511 Camera *cmm_node = DCAST(Camera, cmm.node());
00512 nout << " active = " << cmm_node->is_active() << endl;
00513 int num_cam_drs = cmm_node->get_num_display_regions();
00514 for (int cd = 0; cd < num_cam_drs; cd++)
00515 nout << " dr = " << (void*)cmm_node->get_display_region(cd) << endl;
00516 }
00517 nout << " active = " << dr->is_active() << endl;
00518 }
00519 }
00520 }
00521 }
00522 }
00523 _graphics_window = win;
00524
00525 return;
00526 }
00527
00528
00529
00530
00531
00532 ChanCfgOverrides::ChanCfgOverrides(void) {}
00533
00534 ChanCfgOverrides::ChanCfgOverrides(const ChanCfgOverrides& c) :
00535 _fields(c._fields) {}
00536
00537 ChanCfgOverrides::~ChanCfgOverrides(void) {}
00538
00539 ChanCfgOverrides& ChanCfgOverrides::operator=(const ChanCfgOverrides& c)
00540 {
00541 _fields = c._fields;
00542 return *this;
00543 }
00544
00545 void ChanCfgOverrides::setField(const Field f, const bool v) {
00546 Types t;
00547 t.setBool(v);
00548 _fields[f] = t;
00549 }
00550
00551 void ChanCfgOverrides::setField(const Field f, const int v) {
00552 Types t;
00553 t.setInt(v);
00554 _fields[f] = t;
00555 }
00556
00557 void ChanCfgOverrides::setField(const Field f, const unsigned int v) {
00558 Types t;
00559 t.setUInt(v);
00560 _fields[f] = t;
00561 }
00562
00563 void ChanCfgOverrides::setField(const Field f, const float v) {
00564 Types t;
00565 t.setFloat(v);
00566 _fields[f] = t;
00567 }
00568
00569 void ChanCfgOverrides::setField(const Field f, const double v) {
00570 Types t;
00571 t.setDouble(v);
00572 _fields[f] = t;
00573 }
00574
00575 void ChanCfgOverrides::setField(const Field f, const std::string& v) {
00576 Types t;
00577 t.setString(v);
00578 _fields[f] = t;
00579 }
00580
00581 void ChanCfgOverrides::setField(const Field f, const char* v) {
00582 Types t;
00583 t.setString(v);
00584 _fields[f] = t;
00585 }
00586
00587 bool ChanCfgOverrides::defined(const Field f) const {
00588 return (_fields.find(f) != _fields.end());
00589 }
00590
00591 bool ChanCfgOverrides::getBool(const Field f) const {
00592 Fields::const_iterator i = _fields.find(f);
00593 const Types t((*i).second);
00594 return t.getBool();
00595 }
00596
00597 int ChanCfgOverrides::getInt(const Field f) const {
00598 Fields::const_iterator i = _fields.find(f);
00599 const Types t((*i).second);
00600 return t.getInt();
00601 }
00602
00603 unsigned int ChanCfgOverrides::getUInt(const Field f) const {
00604 Fields::const_iterator i = _fields.find(f);
00605 const Types t((*i).second);
00606 return t.getUInt();
00607 }
00608
00609 float ChanCfgOverrides::getFloat(const Field f) const {
00610 Fields::const_iterator i = _fields.find(f);
00611 const Types t((*i).second);
00612 return t.getFloat();
00613 }
00614
00615 double ChanCfgOverrides::getDouble(const Field f) const {
00616 Fields::const_iterator i = _fields.find(f);
00617 const Types t((*i).second);
00618 return t.getDouble();
00619 }
00620
00621 std::string ChanCfgOverrides::getString(const Field f) const {
00622 Fields::const_iterator i = _fields.find(f);
00623 const Types t((*i).second);
00624 return t.getString();
00625 }