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

Scene.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 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: Scene.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.86 $       $Date: 2012/03/13 18:41:56 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * The Scene object, which maintains a list of Displayable objects and
00020  * draws them to a DisplayDevice.
00021  * Each Scene has a list of Displayable objects, and also a list of display
00022  * commands.  The command lists are used to draw the objects, the Displayable
00023  * objects to prepare and update objects for drawing.
00024  *
00025  ***************************************************************************/
00026 
00027 #include "Scene.h"
00028 #include "DisplayDevice.h"
00029 #include "Inform.h"
00030 #include "DispCmds.h"
00031 #include "utilities.h"
00032 #include "FileRenderList.h"
00033 #include "FileRenderer.h"
00034 
00035 static const int num_scalemethods = 12;
00036 static const ColorScale defScales[] = {
00037  { {1.0, 0.0, 0.0}, {1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, "RWB"},
00038  { {0.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, "BWR"},
00039  { {1.0, 0.0, 0.0}, {0.5, 0.5, 0.5}, {0.0, 0.0, 1.0}, "RGryB"},
00040  { {0.0, 0.0, 1.0}, {0.5, 0.5, 0.5}, {1.0, 0.0, 0.0}, "BGryR"},
00041  { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, "RGB"},
00042  { {0.0, 0.0, 1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, "BGR"},
00043  { {1.0, 0.0, 0.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, "RWG"},
00044  { {0.0, 1.0, 0.0}, {1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, "GWR"},
00045  { {0.0, 1.0, 0.0}, {1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, "GWB"},
00046  { {0.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, "BWG"},
00047  { {0.0, 0.0, 0.0}, {0.5, 0.5, 0.5}, {1.0, 1.0, 1.0}, "BlkW"},
00048  { {1.0, 1.0, 1.0}, {0.5, 0.5, 0.5}, {0.0, 0.0, 0.0}, "WBlk"}
00049 };
00050 
00051 // maybe VMD should be using a color wheel scheme
00052 // to make it easier to pick contrasting and complementary 
00053 // colors.
00054 static const char *defColorNames[REGCLRS] = {
00055   "blue",    "red",    "gray",    "orange",  
00056   "yellow",  "tan",    "silver",  "green",  
00057   "white",   "pink",   "cyan",   "purple",
00058   "lime",    "mauve",  "ochre",  "iceblue", 
00059 
00060   // XXX black is expected to be at the end of the list
00061   "black"
00062 
00063 #if (REGCLRS > 17)
00064  ,"yellow2",  "yellow3",   "green2",    "green3",
00065   "cyan2",    "cyan3",     "blue2",     "blue3",
00066   "violet",   "violet2",   "magenta",   "magenta2",  
00067   "red2",     "red3",      "orange2",   "orange3"
00068 #endif
00069 
00070 };
00071 
00072 const float Scene::defaultColor[] = {
00073    0.0f,   0.0f, 1.00f,  1.0f,  0.0f,  0.0f, // BLUE, RED
00074    0.35f, 0.35f, 0.35f,  1.0f,  0.5f,  0.0f, // GREY, ORANGE
00075    1.0f,   1.0f,  0.0f,  0.5f,  0.5f,  0.2f, // YELLOW, TAN
00076    0.6f,   0.6f,  0.6f,  0.0f,  1.0f,  0.0f, // SILVER, GREEN
00077    1.0f,   1.0f,  1.0f,  1.0f,  0.6f,  0.6f, // WHITE, PINK
00078    0.25f, 0.75f, 0.75f, 0.65f,  0.0f, 0.65f, // CYAN, PURPLE
00079    0.5f,   0.9f,  0.4f,  0.9f,  0.4f,  0.7f, // LIME, MAUVE
00080    0.5f,   0.3f,  0.0f,  0.5f,  0.5f, 0.75f, // OCHRE, ICEBLUE
00081 
00082    // XXX black is expected to be at the end of the list
00083    0.0f,   0.0f,  0.0f                       // BLACK
00084   
00085 #if (REGCLRS > 17)
00086   ,0.88f, 0.97f, 0.02f,  0.55f, 0.90f, 0.02f, // yellow
00087    0.00f, 0.90f, 0.04f,  0.00f, 0.90f, 0.50f, // green
00088    0.00f, 0.88f, 1.00f,  0.00f, 0.76f, 1.00f, // cyan
00089    0.02f, 0.38f, 0.67f,  0.01f, 0.04f, 0.93f, // blue
00090    0.27f, 0.00f, 0.98f,  0.45f, 0.00f, 0.90f, // violet
00091    0.90f, 0.00f, 0.90f,  1.00f, 0.00f, 0.66f, // magenta
00092    0.98f, 0.00f, 0.23f,  0.81f, 0.00f, 0.00f, // red
00093    0.89f, 0.35f, 0.00f,  0.96f, 0.72f, 0.00f  // orange
00094 #endif
00095 
00096 };
00097 
00098 
00100 class DisplayColor : public Displayable {
00101 private:
00102   int colorCat;
00103   int dcindex;
00104   int dccolor;
00105   int changed;
00106  
00107 protected:
00108   void do_color_changed(int cat) {
00109     if (cat == colorCat) {
00110       dccolor = scene->category_item_value(colorCat, dcindex);
00111       changed = 1;
00112     }
00113   } 
00114   void do_color_rgb_changed(int color) {
00115     if (color == dccolor) 
00116       changed = 1;
00117   }
00118    
00119 public:
00120   DisplayColor(Displayable *d, const char *coloritemname, int colorindex)
00121   : Displayable(d), changed(0) {
00122     // Query the index of the Display color category, or add it if necessary
00123     colorCat = scene->category_index("Display");
00124     if (colorCat == -1) {
00125       colorCat = scene->add_color_category("Display");
00126     } 
00127     dcindex = scene->add_color_item(colorCat, coloritemname, colorindex);
00128     do_color_changed(colorCat);
00129   }
00130   int color_changed() const { return changed; }
00131   void clear_changed() { changed = 0; }
00132   int color_id() const { return dccolor; }
00133 };
00134 
00135 
00137 Scene::Scene() : root(this) {
00138   set_background_mode(0);
00139   reset_lights();
00140 
00141   // initialize color names and values
00142   int i;
00143   for (i=BEGREGCLRS; i<REGCLRS; i++) {
00144     colorNames.add_name(defColorNames[i], i);
00145     set_color_value(i, defaultColor + 3*i);
00146   }
00147   //initialize color scale info
00148   for (i=0; i<num_scalemethods; i++) 
00149     colorScales.append(defScales[i]);
00150   scaleMethod = 0;
00151   scaleMin = 0.1f;
00152   scaleMax = 1.0f;
00153   scaleMid = 0.5f;
00154   create_colorscale();
00155 
00156   // background color 
00157   background = new DisplayColor(&root, "Background", REGBLACK);
00158   background_color_changed = 0;
00159   background_color_id = 0;
00160 
00161   // background gradient colors
00162   backgradtop = new DisplayColor(&root, "BackgroundTop", REGBLACK);
00163   backgradtop_color_changed = 0;
00164   backgradtop_color_id = 0;
00165   backgradbot = new DisplayColor(&root, "BackgroundBot", REGBLUE2);
00166   backgradbot_color_changed = 0;
00167   backgradbot_color_id = 0;
00168 
00169   // foreground color
00170   foreground = new DisplayColor(&root, "Foreground", REGWHITE);
00171   foreground_color_changed = 0;
00172   foreground_color_id = 0;
00173 }
00174 
00176 Scene::~Scene(void) {
00177   for (int i=0; i<categories.num(); i++) delete categories.data(i);
00178 }
00179 
00181 
00182 // Set background drawing mode 
00183 void Scene::set_background_mode(int mode) {
00184   backgroundmode = mode;
00185   backgroundmode_changed = 1;
00186 }
00187 
00188 // Query background drawing mode 
00189 int Scene::background_mode(void) {
00190   return backgroundmode;
00191 }
00192 
00193 
00194 //
00195 // routines to deal with light sources
00196 //
00197   
00198 // default light data
00199 static const float def_light_color[3] = { 1.0, 1.0, 1.0 };
00200 static const float def_light_pos[DISP_LIGHTS][3] = {
00201         { -0.1f, 0.1f,  1.0f }, {  1.0f,  2.0f, 0.5f },
00202         { -1.0f, 2.0f, -1.0f }, { -1.0f, -1.0f, 0.0f }
00203 };
00204 static const float def_adv_light_pos[DISP_LIGHTS][3] = {
00205         { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 
00206         { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }
00207 };
00208 
00209 static const int def_light_on[DISP_LIGHTS] = { TRUE, TRUE, FALSE, FALSE };
00210 
00211 void Scene::define_light(int n, const float *color, const float *position) {
00212   if (n < 0 || n >= DISP_LIGHTS)
00213     return;
00214   
00215   for (int i=0; i < 3; i++) {
00216     lightState[n].color[i] = color[i];
00217     lightState[n].pos[i] = position[i];
00218   }
00219   light_changed = 1;
00220 }
00221 
00222 void Scene::activate_light(int n, int turnon) {
00223   if (n < 0 || n >= DISP_LIGHTS )
00224     return;
00225   lightState[n].on = turnon;
00226   light_changed = 1;
00227 }
00228 
00229 void Scene::rotate_light(int n, float theta, char axis) {
00230   if (n < 0 || n >= DISP_LIGHTS)
00231     return;
00232   Matrix4 mat;
00233   mat.rot(theta,axis);
00234   mat.multpoint3d(lightState[n].pos,lightState[n].pos);
00235   light_changed = 1;
00236 }
00237 
00238 void Scene::move_light(int n, const float *p) {
00239   if (n < 0 || n >= DISP_LIGHTS) return;
00240   for (int i=0; i<3; i++) lightState[n].pos[i] = p[i];
00241   light_changed = 1;
00242 }
00243 
00244 const float *Scene::light_pos(int n) const {
00245   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00246   return lightState[n].pos;
00247 }
00248 
00249 const float *Scene::light_pos_default(int n) const {
00250   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00251   return def_light_pos[n];
00252 }
00253 
00254 const float *Scene::light_color(int n) const {
00255   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00256   return lightState[n].color;
00257 }
00258 
00259 const float *Scene::light_color_default(int n) const {
00260   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00261   return def_light_color;
00262 }
00263 
00264 
00265 void Scene::define_adv_light(int n, const float *color, 
00266                                   const float *position,
00267                                   float constant, float linear, float quad,
00268                                   float *spotdir, 
00269                                   float fallstart, float fallend, int spoton) {
00270   if (n < 0 || n >= DISP_LIGHTS)
00271     return;
00272   
00273   for (int i=0; i < 3; i++) {
00274     advLightState[n].color[i] = color[i];
00275     advLightState[n].pos[i] = position[i];
00276     advLightState[n].spotdir[i] = spotdir[i];
00277   }
00278   advLightState[n].constfactor = constant;
00279   advLightState[n].linearfactor = linear;
00280   advLightState[n].quadfactor = quad;
00281   advLightState[n].fallstart = fallstart;
00282   advLightState[n].fallend = fallend;
00283   advLightState[n].spoton = spoton;
00284   adv_light_changed = 1;
00285 }
00286 
00287 void Scene::activate_adv_light(int n, int turnon) {
00288   if (n < 0 || n >= DISP_LIGHTS )
00289     return;
00290   advLightState[n].on = turnon;
00291   adv_light_changed = 1;
00292 }
00293 
00294 void Scene::move_adv_light(int n, const float *p) {
00295   if (n < 0 || n >= DISP_LIGHTS) return;
00296   for (int i=0; i<3; i++) 
00297     advLightState[n].pos[i] = p[i];
00298   adv_light_changed = 1;
00299 }
00300 
00301 const float *Scene::adv_light_pos(int n) const {
00302   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00303   return advLightState[n].pos;
00304 }
00305 
00306 const float *Scene::adv_light_pos_default(int n) const {
00307   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00308   return def_adv_light_pos[n];
00309 }
00310 
00311 const float *Scene::adv_light_color(int n) const {
00312   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00313   return advLightState[n].color;
00314 }
00315 
00316 const float *Scene::adv_light_color_default(int n) const {
00317   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00318   return def_light_color;
00319 }
00320 
00321 void Scene::adv_light_attenuation(int n, float constant, float linear,
00322                                   float quad) {
00323   if (n < 0 || n >= DISP_LIGHTS) return;
00324   advLightState[n].constfactor = constant;
00325   advLightState[n].linearfactor = linear;
00326   advLightState[n].quadfactor = quad;
00327 }
00328 
00329 void Scene::adv_light_get_attenuation(int n, float &constant, float &linear,
00330                                       float &quad) const {
00331   if (n < 0 || n >= DISP_LIGHTS) return;
00332   constant = advLightState[n].constfactor;
00333   linear   = advLightState[n].linearfactor;
00334   quad     = advLightState[n].quadfactor;
00335 }
00336 
00337 void Scene::adv_light_spotlight(int n, float *spotdir, float fallstart, 
00338                                 float fallend, int spoton) {
00339   if (n < 0 || n >= DISP_LIGHTS) return;
00340   advLightState[n].fallstart = fallstart;
00341   advLightState[n].fallend = fallend;
00342   advLightState[n].spoton = spoton;
00343   for (int i=0; i<3; i++) 
00344     advLightState[n].spotdir[i] = spotdir[i];
00345 }
00346 
00347 const float *Scene::adv_light_get_spotlight(int n, float &fallstart, 
00348                                             float &fallend, int &spoton) const {
00349   if (n < 0 || n >= DISP_LIGHTS) return NULL;
00350   fallstart = advLightState[n].fallstart;
00351   fallend   =  advLightState[n].fallend;
00352   spoton    = advLightState[n].spoton;
00353   return advLightState[n].spotdir;
00354 }
00355 
00356 void Scene::reset_lights(void) {
00357   int i;
00358 
00359   // standard directional lights
00360   for (i=0; i<DISP_LIGHTS; i++) { 
00361     define_light(i, def_light_color, def_light_pos[i]);
00362     activate_light(i, def_light_on[i]);
00363   }
00364   light_changed = 1;
00365 
00366   // advanced lights
00367   for (i=0; i<DISP_LIGHTS; i++) { 
00368     float spotdir[] = { 0.0f, 0.0f, 1.0f };
00369     define_adv_light(i, def_light_color, def_light_pos[i],
00370                      1.0f, 0.0f, 0.0f,
00371                      spotdir, 0.3f, 0.7f, 0);
00372     activate_adv_light(i, 0);
00373   }
00374   adv_light_changed = 1;
00375 }
00376 
00377 
00378 // prepare all registered Displayables
00379 int Scene::prepare() {
00380   background_color_changed = background->color_changed();
00381   background_color_id = background->color_id();
00382   background->clear_changed();
00383 
00384   backgradtop_color_changed = backgradtop->color_changed();
00385   backgradtop_color_id = backgradtop->color_id();
00386   backgradtop->clear_changed();
00387 
00388   backgradbot_color_changed = backgradbot->color_changed();
00389   backgradbot_color_id = backgradbot->color_id();
00390   backgradbot->clear_changed();
00391 
00392   foreground_color_changed = foreground->color_changed();
00393   foreground_color_id = foreground->color_id();
00394   foreground->clear_changed();
00395 
00396   return root.draw_prepare() || backgroundmode_changed || light_changed || 
00397          background_color_changed || 
00398          backgradtop_color_changed || backgradbot_color_changed || 
00399          foreground_color_changed;
00400 }
00401 
00402 // draws the scene to the given DisplayDevice
00403 // this is the only Scene which tells the display to do graphics commands
00404 //
00405 // XXX implementation of multi-pass rendering, accumulation buffers,
00406 //     and better snapshot behavior will require modifications to this
00407 //     mechanism.  The current system is very simple minded, and doesn't
00408 //     allow for property-based sorting of geometry, occlusion culling 
00409 //     algorithms, etc.  This needs to be changed.
00410 //
00411 // XXX note, this method should really be a 'const' method since
00412 //     it is run concurrently by several processes that share memory, but
00413 //     we can't actually write it that way since the locking routines do
00414 //     indeed write to lock variables.  The code in draw() should be written
00415 //     as though it were a const method however, at least in terms of what
00416 //     state is changed in the Scene class or subclass.
00417 //
00418 void Scene::draw(DisplayDevice *display) {
00419   if (!display)
00420     return;
00421 
00422   if (!display->is_renderer_process()) // master process doesn't draw
00423     return;
00424 
00425   // check background rendering mode
00426   if (backgroundmode_changed) {
00427     display->set_background_mode(backgroundmode);
00428   }
00429 
00430   // XXX Make a Displayable for lights, as we do for background color, and
00431   //     have a DispCmd for turning lights on and off.
00432   if (light_changed) {
00433     // set up the lights
00434     for (int i=0; i<DISP_LIGHTS; i++) {
00435       display->do_define_light(i, lightState[i].color, lightState[i].pos);
00436       display->do_activate_light(i, lightState[i].on);
00437     }
00438   }
00439 
00440 #if 0
00441   // XXX advanced lights are not yet implemented by displays
00442   // XXX Make a Displayable for lights, as we do for background color, and
00443   //     have a DispCmd for turning lights on and off.
00444   if (adv_light_changed) {
00445     // set up the lights
00446     for (int i=0; i<DISP_LIGHTS; i++) {
00447       display->do_define_light(i, lightState[i].color, lightState[i].pos);
00448       display->do_activate_light(i, lightState[i].on);
00449     }
00450   }
00451 #endif
00452 
00453   // update colors
00454   display->use_colors(colorData);
00455 
00456   // set the background color if any color definitions changed, or if the
00457   // the color assigned to background changed.  
00458   // XXX Make a DispCmd for background color so that background color can
00459   //     be handled automatically by the renderers, rather than special-cased
00460   //     as we do here.  This should work because the background displayable is
00461   //     the first item traversed in the scene graph. 
00462   if (background_color_changed) {
00463     display->set_background(color_value(background_color_id));
00464   }
00465 
00466   // set the background gradient colors if any definitions changed, or if
00467   // the color assigned to the gradient changed.
00468   if (backgradtop_color_changed || backgradbot_color_changed) {
00469     display->set_backgradient(color_value(backgradtop->color_id()),
00470                               color_value(backgradbot->color_id()));
00471   }
00472 
00473   // clear the display and set the viewport correctly
00474   display->prepare3D(TRUE);
00475 
00476   // on some machines with broken stereo implementations, we have
00477   // to draw in stereo even when VMD is set for mono mode
00478   // XXX this is all very ugly, and while this trick works for drawing
00479   // in normal mode, it doesn't fix the other single-buffer "stereo"
00480   // modes, since they don't fall into this test case.  Scene doesn't have
00481   // intimate knowledge of the details of the display subclass's 
00482   // stereo mode implementations, so a future rewrite will probably have
00483   // to move all of this code into the DisplayDevice class, with Scene
00484   // simply passing in a bunch of parameters so the display subclass
00485   // can deal with these problems for itself.
00486   if (display->forced_stereo_draws() && !(display->stereo_mode())) {
00487     display->left();  // this will be done as normal() since stereo is off
00488                       // but we'll actually draw to GL_BACK_LEFT
00489     display->prepareOpaque();
00490     root.draw(display);
00491     if (display->prepareTrans()) {
00492       root.draw(display);
00493     }
00494 
00495     display->right(); // this will be done as normal() since stereo is off
00496                       // but we'll actually draw to GL_BACK_RIGHT
00497     display->prepareOpaque();
00498     root.draw(display);
00499     if (display->prepareTrans()) {
00500       root.draw(display);
00501     }
00502   } else {
00503     // draw left eye first, if stereo
00504     if (display->stereo_mode())
00505       display->left();
00506     else
00507       display->normal();
00508 
00509     // draw all the objects for normal, or left eye position
00510     display->prepareOpaque();
00511     root.draw(display);
00512 
00513     if (display->prepareTrans()) {
00514       root.draw(display);
00515     }
00516    
00517     // now draw right eye, if in stereo
00518     if (display->stereo_mode()) {
00519       display->right();
00520       display->prepareOpaque();
00521       root.draw(display);
00522 
00523       if (display->prepareTrans()) {
00524         root.draw(display);
00525       }
00526     } 
00527   }  
00528 
00529   display->render_done();
00530   
00531   // update the display
00532   display->update(TRUE);
00533 }
00534 
00535 // draw the scene to a file in a given format, trying to match the
00536 // view of the given DisplayDevice as closely as possible
00537 // returns TRUE if successful, FALSE if not
00538 int Scene::filedraw(FileRenderer *render, const char *filename, 
00539                     DisplayDevice *display) {
00540   int i;
00541 
00542   // Copy all relevant info from the current main DisplayDevice
00543   (*((DisplayDevice *)render)) = (*display);
00544 
00545   // set up the lights
00546   for (i=0; i<DISP_LIGHTS; i++) {
00547     if (lightState[i].on)
00548       render->do_define_light(i, lightState[i].color, lightState[i].pos);
00549     render->do_activate_light(i, lightState[i].on);
00550   }
00551 
00552   // set up the advanced lights
00553   for (i=0; i<DISP_LIGHTS; i++) {
00554     if (lightState[i].on)
00555       render->do_define_adv_light(i, 
00556                                   advLightState[i].color,
00557                                   advLightState[i].pos,
00558                                   advLightState[i].constfactor,
00559                                   advLightState[i].linearfactor,
00560                                   advLightState[i].quadfactor,
00561                                   advLightState[i].spotdir,
00562                                   advLightState[i].fallstart,
00563                                   advLightState[i].fallend,
00564                                   advLightState[i].spoton);
00565     render->do_activate_adv_light(i, advLightState[i].on);
00566   }
00567 
00568   // set up the colors
00569   render->use_colors(colorData);
00570   render->set_background(color_value(background->color_id()));
00571   render->set_backgradient(color_value(backgradtop->color_id()),
00572                            color_value(backgradbot->color_id()));
00573 
00574   // returns FALSE if not able to open file
00575   if (!render -> open_file(filename)) {
00576     return FALSE;
00577   }
00578   // writes the header
00579   render->prepare3D(TRUE);
00580 
00581   // draw the scene to the file
00582   root.draw(render);
00583 
00584   // write the trailer and close
00585   render->render_done();
00586   render->update(TRUE);
00587 
00588   // rendering was successful
00589   return TRUE;
00590 }
00591 
00592 // state updates have to be done outside of the draw routine to prevent
00593 // race conditions when multiple slave renderers execute the draw() code.
00594 void Scene::draw_finished() {
00595   // only master process changes state flags
00596   backgroundmode_changed=0; // reset background mode change flag
00597   light_changed = 0;        // reset light changing state cache
00598   adv_light_changed = 0;    // reset light changing state cache
00599 }
00600 
00601 // create the color scale based on current settings
00602     
00604 // definitions for scales with 3 colors
00605 // 1 at val = 0; 0 at mid and greater
00606 static float slope3_lower(float mid, float val) {
00607   if (val > mid) return 0.0f;
00608   if (mid == 0) return 1.0f;
00609   return (1.0f - val / mid);
00610 }
00611   
00612 // 1 at val = 1; 0 at mid and lesser
00613 static float slope3_upper(float mid, float val) {
00614   if (val < mid) return 0.0f;
00615   if (mid == 1) return 1.0f;
00616   return (1.0f - (1.0f - val) / (1.0f - mid));
00617 } 
00618     
00619 // 1 at val = mid; 0 at val = 0 an 1
00620 static float slope3_middle(float mid, float val) {
00621   if (val < mid) {
00622     return val / mid;
00623   }
00624   if (val > mid) { 
00625     return (1-val) / (1-mid);
00626   } 
00627   return 1.0;
00628 }
00629   
00630     
00631 // given RGB values at (0,mid,1), return the correct RGB triplet
00632 static void scale_color(const float *lowRGB, const float *midRGB, 
00633                         const float *highRGB,
00634                         float mid, float val, float scaleMin, float *rgb) {
00635   float w1 = slope3_lower(mid, val);
00636   float w2 = slope3_middle(mid, val);
00637   float w3 = slope3_upper(mid, val);
00638   float wsum = (w1 + w2 + w3);
00639 
00640   rgb[0] = (lowRGB[0]*w1 + midRGB[0]*w2 + highRGB[0]*w3) / wsum + scaleMin;
00641   rgb[1] = (lowRGB[1]*w1 + midRGB[1]*w2 + highRGB[1]*w3) / wsum + scaleMin;
00642   rgb[2] = (lowRGB[2]*w1 + midRGB[2]*w2 + highRGB[2]*w3) / wsum + scaleMin;
00643 
00644   clamp_color(rgb);
00645 }
00646 
00647 void Scene::create_colorscale() {
00648   const ColorScale &scale = colorScales[scaleMethod];
00649   for (int i=0; i<MAPCLRS; i++) {
00650     float *rcol = colorData + 3*(BEGMAP + i);
00651     float relpos = float(i) / float(MAPCLRS -1);
00652     scale_color(scale.min, scale.mid, scale.max, scaleMid, relpos, scaleMin, 
00653         rcol);
00654   }
00655   root.color_scale_changed();
00656 }
00657 
00658 int Scene::nearest_index(float r, float g, float b) const {
00659    const float *rcol = color_value(BEGREGCLRS);  // get the solid colors
00660    float lsq = r - rcol[0]; lsq *= lsq;
00661    float tmp = g - rcol[1]; lsq += tmp * tmp;
00662          tmp = b - rcol[2]; lsq += tmp * tmp;
00663    float best = lsq;
00664    int bestidx = BEGREGCLRS;
00665    for (int n= BEGREGCLRS+1; n < (BEGREGCLRS + REGCLRS); n++) {
00666       rcol = color_value(n); 
00667       lsq = r - rcol[0]; lsq *= lsq;
00668       tmp = g - rcol[1]; lsq += tmp * tmp;
00669       tmp = b - rcol[2]; lsq += tmp * tmp;
00670       if (lsq < best) {
00671        best = lsq;
00672        bestidx = n;
00673       }
00674    }
00675    return bestidx;
00676 }
00677 
00678 int Scene::get_colorscale_colors(int whichScale, 
00679       float min[3], float mid[3], float max[3]) {
00680   if (whichScale < 0 || whichScale >= colorScales.num())
00681     return FALSE;
00682   const ColorScale &scale = colorScales[whichScale];
00683   for (int i=0; i<3; i++) {
00684     min[i] = scale.min[i];
00685     mid[i] = scale.mid[i];
00686     max[i] = scale.max[i];
00687   }
00688   return TRUE;
00689 }
00690 
00691 int Scene::set_colorscale_colors(int whichScale, 
00692       const float min[3], const float mid[3], const float max[3]) {
00693   if (whichScale < 0 || whichScale >= colorScales.num())
00694     return FALSE;
00695   ColorScale &scale = colorScales[whichScale];
00696   for (int i=0; i<3; i++) {
00697     scale.min[i] = min[i];
00698     scale.mid[i] = mid[i];
00699     scale.max[i] = max[i];
00700   }
00701   create_colorscale();
00702   return TRUE;
00703 }
00704 

Generated on Tue May 22 01:48:11 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002