Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

py_display.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: py_display.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.43 $       $Date: 2019/10/28 20:47:13 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *  Python OpenGL display control interface.
00019  ***************************************************************************/
00020 
00021 #include "py_commands.h"
00022 #include "VMDApp.h"
00023 #include "DisplayDevice.h"
00024 
00025 static const char update_doc[] =
00026 "Force a render window update, without updating FLTK menus";
00027 static PyObject* py_update(PyObject *self, PyObject *args) {
00028   VMDApp *app;
00029   if (!(app = get_vmdapp()))
00030     return NULL;
00031 
00032   app->display_update();
00033 
00034   Py_INCREF(Py_None);
00035   return Py_None;
00036 }
00037 
00038 
00039 static const char update_ui_doc[] =
00040 "Update the render window and all user interfaces";
00041 static PyObject* py_update_ui(PyObject *self, PyObject *args) {
00042   VMDApp *app;
00043   if (!(app = get_vmdapp()))
00044     return NULL;
00045 
00046   app->display_update_ui();
00047 
00048   Py_INCREF(Py_None);
00049   return Py_None;
00050 }
00051 
00052 
00053 static const char update_on_doc[] =
00054 "Tell VMD to regularly update display and GUI menus";
00055 static PyObject* py_update_on(PyObject *self, PyObject *args) {
00056   VMDApp *app;
00057   if (!(app = get_vmdapp()))
00058     return NULL;
00059 
00060   app->display_update_on(1);
00061 
00062   Py_INCREF(Py_None);
00063   return Py_None;
00064 }
00065 
00066 
00067 static const char update_off_doc[] =
00068 "Stop updating the display. Updates will only occur when `update()` is called";
00069 static PyObject* py_update_off(PyObject *self, PyObject *args) {
00070   VMDApp *app;
00071   if (!(app = get_vmdapp()))
00072     return NULL;
00073 
00074   app->display_update_on(0);
00075 
00076   Py_INCREF(Py_None);
00077   return Py_None;
00078 }
00079 
00080 
00081 static const char set_doc[] =
00082 "Sets display properties. One or more properties may be set at a time.\n\n"
00083 "Args:\n"
00084 "    eyesep (float): Eye separation\n"
00085 "    focallength (float): Focal length\n"
00086 "    height (float): Screen height relative to the camera\n"
00087 "    distance (float): Screen distance relative to the camera\n"
00088 "    nearclip (float): Near clipping plane distance\n"
00089 "    farclip (float): Far clipping plane distance\n"
00090 "    antialias (bool): If antialiasing is on\n"
00091 "    depthcueue (bool): If depth cueuing is used\n"
00092 "    culling (bool): If backface culling is used. Can reduce performance\n"
00093 "    stereo (bool): If stereo mode is on\n"
00094 "    projection (str): Projection mode, in [Perspective, Orthographic]\n"
00095 "    size (list of 2 ints): Display window size, in px\n"
00096 "    ambientocclusion (bool): If ambient occlusion is used\n"
00097 "    aoambient (float): Amount of ambient light\n"
00098 "    aodirect (float): Amount of direct light\n"
00099 "    shadows (bool): If shadows should be rendered\n"
00100 "    dof (bool): If depth of field effects should be rendered\n"
00101 "    dof_fnumber (float): F-number for depth of field effects\n"
00102 "    dof_focaldist (float): Focal distance for depth of field effects";
00103 static PyObject* py_set(PyObject *self, PyObject *args, PyObject *kwargs) {
00104   const char *kwlist[] = {"eyesep", "focallength", "height", "distance",
00105                           "nearclip", "farclip", "antialias", "depthcue",
00106                           "culling", "stereo", "projection", "size",
00107                           "ambientocclusion", "aoambient", "aodirect",
00108                           "shadows", "dof", "dof_fnumber", "dof_focaldist",
00109                           NULL};
00110   float eyesep, focallength, height, distance, nearclip, farclip;
00111   float aoambient, aodirect, dof_fnumber, dof_focaldist;
00112   int antialias, depthcue, culling, ao, shadows, dof;
00113   char *stereo, *projection;
00114   int num_keys = 19;
00115   PyObject *size;
00116   int i, w, h;
00117 
00118   if (!PyArg_ParseTupleAndKeywords(args, kwargs,
00119                                    "|ffffffO&O&O&ssOO&ffO&O&ff:display.set",
00120                                    (char**) kwlist, &eyesep, &focallength,
00121                                    &height, &distance, &nearclip, &farclip,
00122                                    convert_bool, &antialias, convert_bool,
00123                                    &depthcue, convert_bool, &culling, &stereo,
00124                                    &projection, &size, convert_bool, &ao,
00125                                    &aoambient, &aodirect, convert_bool,
00126                                    &shadows, convert_bool, &dof, &dof_fnumber,
00127                                    &dof_focaldist))
00128     return NULL;
00129 
00130   VMDApp *app;
00131   if (!(app = get_vmdapp()))
00132     return NULL;
00133 
00134   /*
00135    * If both nearclip and farclip will be set, the setting can fail even if
00136    * both new values define a valid range, as the setting is performed on one
00137    * clip plane at a time and it is compared to the *current* value of the
00138    * other. Here, we set both clip planes to be in valid locations beforehand
00139    * so this failure won't happen.
00140    */
00141   if (PyDict_GetItemString(kwargs, "nearclip") && 
00142       PyDict_GetItemString(kwargs, "farclip")) {
00143     if (nearclip >= farclip)
00144       goto cliperror;
00145 
00146     if (nearclip >= app->display->far_clip())
00147       app->display_set_farclip(nearclip + 1.0, 0);
00148 
00149     if (farclip <= app->display->near_clip())
00150       app->display_set_nearclip(farclip - 1.0, 0);
00151   }
00152 
00153   // Use the kwargs dictionary directly to get the commands
00154   // XXX Both this approach and the one taken in the implementation
00155   //     of py_get() below are grossly inefficient. Since they aren't
00156   //     using a hash table scheme to match keyword strings each case,
00157   //     they each perform large numbers of redundant string compares.
00158   //     Creating a hash table for each call would also be inefficient,
00159   //     so ideally we'd make one during module creation and use it 
00160   //     for the life of the interpreter.
00161   for (i = 0; i < num_keys; i++) {
00162     if (!PyDict_GetItemString(kwargs, kwlist[i]))
00163       continue;
00164 
00165     switch (i) {
00166       case 0: app->display_set_eyesep(eyesep); break;
00167       case 1: app->display_set_focallen(focallength); break;
00168       case 2: app->display_set_screen_height(height); break;
00169       case 3: app->display_set_screen_distance(distance); break;
00170       case 4:
00171         if (nearclip >= app->display->far_clip())
00172           goto cliperror;
00173         app->display_set_nearclip(nearclip, 0);
00174         break;
00175       case 5:
00176         if (farclip <= app->display->near_clip())
00177           goto cliperror;
00178         app->display_set_farclip(farclip, 0);
00179         break;
00180       case 6: app->display_set_aa(antialias); break;
00181       case 7: app->display_set_depthcue(depthcue); break;
00182       case 8: app->display_set_culling(culling); break;
00183       case 9: app->display_set_stereo(stereo); break;
00184       case 10:
00185         if (!app->display_set_projection(projection)) {
00186           PyErr_SetString(PyExc_ValueError, "Invalid projection");
00187           goto failure;
00188         }
00189         break;
00190       case 11:
00191         if (!PySequence_Check(size) || PySequence_Size(size) != 2
00192             || is_pystring(size)) {
00193           PyErr_SetString(PyExc_ValueError,
00194                           "size argument must be a two-element list or tuple");
00195           goto failure;
00196         }
00197         w = as_int(PySequence_GetItem(size, 0));
00198         h = as_int(PySequence_GetItem(size, 1));
00199         if (PyErr_Occurred())
00200             goto failure;
00201 
00202         app->display_set_size(w, h);
00203 
00204         break;
00205       case 12: app->display_set_ao(ao); break;
00206       case 13: app->display_set_ao_ambient(aoambient); break;
00207       case 14: app->display_set_ao_direct(aodirect); break;
00208       case 15: app->display_set_shadows(shadows); break;
00209       case 16: app->display_set_dof(dof); break;
00210       case 17: app->display_set_dof_fnumber(dof_fnumber); break;
00211       case 18: app->display_set_dof_focal_dist(dof_focaldist); break;
00212       default: ;
00213     } // end switch
00214   }   // end loop over keys
00215 
00216   Py_INCREF(Py_None);
00217   return Py_None;
00218 
00219 cliperror:
00220   PyErr_SetString(PyExc_ValueError, "Invalid clip plane settings. Near clip "
00221                   "plane cannot be larger than far clip plane");
00222 failure:
00223     return NULL;
00224 }
00225 
00226 
00227 static char get_doc[] =
00228 "Query display properties\n\n"
00229 "Args:\n"
00230 "    query (str): Property to query. See keywords for `display.set()` for a\n"
00231 "        comprehensive list of properties.\n"
00232 "Returns:\n"
00233 "    (either float, bool, list of 2 ints, or str): Value of queried parameter\n"
00234 "        with datatype depending on the parameter type. See `display.set()`\n"
00235 "        for a list of all parameters and types.";
00236 static PyObject* py_get(PyObject *self, PyObject *args, PyObject *kwargs) {
00237   const char *kwlist[] = {"query", NULL};
00238   PyObject *result = NULL;
00239   char *key;
00240 
00241   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:display.get",
00242                                   (char**) kwlist,  &key))
00243     return NULL;
00244 
00245   VMDApp *app;
00246   if (!(app = get_vmdapp()))
00247     return NULL;
00248 
00249   DisplayDevice *disp = app->display;
00250 
00251   // XXX Both this approach and the one taken in the implementation
00252   //     of py_set() above are grossly inefficient. Since they aren't
00253   //     using a hash table scheme to match keyword strings each case,
00254   //     they each perform large numbers of redundant string compares.
00255   //     Creating a hash table for each call would also be inefficient,
00256   //     so ideally we'd make one during module creation and use it 
00257   //     for the life of the interpreter.
00258   if (!strcmp(key, "eyesep")) {
00259     result = PyFloat_FromDouble(disp->eyesep());
00260 
00261   } else if (!strcmp(key, "focallength")) {
00262     result = PyFloat_FromDouble(disp->eye_dist());
00263 
00264   } else if (!strcmp(key, "height")) {
00265     result = PyFloat_FromDouble(disp->screen_height());
00266 
00267   } else if (!strcmp(key, "distance")) {
00268     result = PyFloat_FromDouble(disp->distance_to_screen());
00269 
00270   } else if (!strcmp(key, "nearclip")) {
00271     result = PyFloat_FromDouble(disp->near_clip());
00272 
00273   } else if (!strcmp(key, "farclip")) {
00274     result = PyFloat_FromDouble(disp->far_clip());
00275 
00276   } else if (!strcmp(key, "antialias")) {
00277     result = disp->aa_enabled() ? Py_True : Py_False;
00278     Py_INCREF(result);
00279 
00280   } else if (!strcmp(key, "depthcue")) {
00281     result = disp->cueing_enabled() ? Py_True : Py_False;
00282     Py_INCREF(result);
00283 
00284   } else if (!strcmp(key, "culling")) {
00285     result = disp->culling_enabled() ? Py_True : Py_False;
00286     Py_INCREF(result);
00287 
00288   } else if (!strcmp(key, "stereo")) {
00289     result = as_pystring(disp->stereo_name(disp->stereo_mode()));
00290 
00291   } else if (!strcmp(key, "projection")) {
00292     result = as_pystring(disp->get_projection());
00293 
00294   } else if (!strcmp(key, "size")) {
00295     int w, h;
00296     app->display_get_size(&w, &h);
00297     result = Py_BuildValue("[i,i]", w, h);
00298 
00299   } else if (!strcmp(key, "ambientocclusion")) {
00300     result = disp->ao_enabled() ? Py_True : Py_False;
00301     Py_INCREF(result);
00302 
00303   } else if (!strcmp(key, "aoambient")) {
00304     result = PyFloat_FromDouble(disp->get_ao_ambient());
00305 
00306   } else if (!strcmp(key, "aodirect")) {
00307     result = PyFloat_FromDouble(disp->get_ao_direct());
00308 
00309   } else if (!strcmp(key, "shadows")) {
00310     result = disp->shadows_enabled() ? Py_True : Py_False;
00311     Py_INCREF(result);
00312 
00313   } else if (!strcmp(key, "dof")) {
00314     result = disp->dof_enabled() ? Py_True : Py_False;
00315     Py_INCREF(result);
00316 
00317   } else if (!strcmp(key, "dof_fnumber")) {
00318     result = PyFloat_FromDouble(disp->get_dof_fnumber());
00319 
00320   } else if (!strcmp(key, "dof_focaldist")) {
00321     result = PyFloat_FromDouble(disp->get_dof_focal_dist());
00322 
00323   } else {
00324     PyErr_Format(PyExc_ValueError, "Invalid query '%s'", key);
00325     goto failure;
00326   }
00327 
00328   if (PyErr_Occurred()) {
00329     PyErr_SetString(PyExc_RuntimeError, "Problem getting display attribute");
00330     goto failure;
00331   }
00332 
00333   return result;
00334 
00335 failure:
00336   Py_XDECREF(result);
00337   return NULL;
00338 }
00339 
00340 
00341 static const char stereomodes_doc[] =
00342 "Get available stereo modes\n\n"
00343 "Returns:\n"
00344 "    (list of str): Available modes";
00345 static PyObject* py_stereomodes(PyObject *self, PyObject *args) {
00346   int j;
00347 
00348   VMDApp *app;
00349   if (!(app = get_vmdapp()))
00350     return NULL;
00351 
00352   DisplayDevice *disp = app->display;  
00353   int num = disp->num_stereo_modes();
00354 
00355   PyObject *newlist = PyList_New(num);
00356   if (!newlist || PyErr_Occurred())
00357     goto failure;
00358 
00359   for (j = 0; j < num; j++) {
00360     PyList_SET_ITEM(newlist, j, as_pystring(disp->stereo_name(j)));
00361     if (PyErr_Occurred())
00362       goto failure;
00363   }
00364 
00365   return newlist;
00366 
00367 failure:
00368   PyErr_SetString(PyExc_RuntimeError, "Problem listing stero modes");
00369   Py_XDECREF(newlist);
00370   return NULL;
00371 }
00372 
00373 
00374 static PyMethodDef DisplayMethods[] = {
00375   {"update", (PyCFunction)py_update, METH_NOARGS, update_doc},
00376   {"update_ui", (PyCFunction)py_update_ui, METH_NOARGS, update_ui_doc},
00377   {"update_on", (PyCFunction)py_update_on, METH_NOARGS, update_on_doc},
00378   {"update_off", (PyCFunction)py_update_off, METH_NOARGS, update_off_doc},
00379   {"set", (PyCFunction)py_set, METH_VARARGS | METH_KEYWORDS, set_doc},
00380   {"get", (PyCFunction)py_get, METH_VARARGS | METH_KEYWORDS, get_doc},
00381   {"stereomodes", (PyCFunction)py_stereomodes, METH_NOARGS, stereomodes_doc},
00382   {NULL, NULL}
00383 };
00384 
00385 
00386 static const char disp_moddoc[] =
00387 "Contains methods to set various parameters in the graphical display, as "
00388 "well as controlling how the UI and render window are updated";
00389 
00390 
00391 #if PY_MAJOR_VERSION >= 3
00392 static struct PyModuleDef displaydef = {
00393   PyModuleDef_HEAD_INIT,
00394   "display",
00395   disp_moddoc,
00396   -1,              // XXX we could benefit from persistent module hash tables 
00397   DisplayMethods,
00398 };
00399 #endif
00400 
00401 
00402 PyObject* initdisplay() {
00403 #if PY_MAJOR_VERSION >= 3
00404   PyObject *m = PyModule_Create(&displaydef);
00405 #else
00406   PyObject *m = Py_InitModule3("display", DisplayMethods, disp_moddoc);
00407 #endif
00408 
00409   // XXX elminate these hard-coded string names by building a list
00410   //     dynamically, e.g., as is done for stereo and other mode name lists
00411   PyModule_AddStringConstant(m, "PROJ_PERSP", "Perspective");
00412   PyModule_AddStringConstant(m, "PROJ_ORTHO", "Orthographic");
00413 
00414   return m;
00415 }
00416 

Generated on Tue Apr 16 02:46:06 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002