First off, I am totally excited to see how much has been happening with
Avogadro and LibAvogadro. Really great, ideas are flowing things are
chaining off each other.
Also, I don’t want to preach, but please try to commit code that is
ready for production. We are already seeing commits of “temporary
hack”. This is really bad. People build on previous commits; if
previous commits are bad, then the code committed on top of the bad code
is ALSO bad. Through no fault of the added code’s author. It also
means when that bad code gets fixed, the added code will probably need
to be fixed too. I am not trying to be a dick or anything, but it’s
important to me and I believe it’s really important to the project.
Software Engineering is important as much as it’s a pain in the ass (it
is trust me) but it really pays off. // end lecture
So here is some stuff I’ve been stewing over while I was gone (couldn’t
sleep being excited). I’ll also find a place for this on the WIKI
somewhere (probably in TODO).
== Selection ==
The biggest issue we must resolved immediately, and before we start
implementing new features/changes is the selection issue; Is selection
part of the model (molecule) or part of the view (glwidget). I don’t
think there are objective benefits which make one better over another,
it’s more about what’s more intuitive to the user. Does a user look at
a molecule and expect that no matter how they view the molecule and
select parts of it, that selection stays the same? Does a user look at
a molecule in one view with one selection and expect that to be
different in a different view? I think in general most of us talking on
IRC believe that it’s more a property of the view than of the model.
This also makes it a bit more flexible since maybe in one view i select
a certain thing to modify it, or in another view i select a different
thing to modify without having to go through and reselect everything.
It is not going to effect features, but whichever way we choose, they
will both have different architectures / functions etc. The underlying
code will be different for sure. Both is easy and doable, we just need
to decide.
== Engines ==
In moving forward with engines in Avogadro and LibAvogadro I am
proposing a few updated to the UI. The main idea would be to have a
list of engines, as you select one in the list, below it you are given
two tabs. The first is the settings for the given engine and the second
is a list of all the objects that are rendered for that engine. By
default, any addition of new atoms / bonds are added to all engines.
From the engine list you should be able to duplicate or add new any
engine based on the EngineFactory’s which are loaded from the plugins.
As for saving settings, we should be able to say “hey, here is the
default list of engines that i would like when i startup Avogadro”. We
also need to consider that at some point we will need to save engine
settings WITH the avogadro file. I’m going to go ahead and assume that
most of this will be taken care of by OpenBabel for which we’ll
eventually have to create our own format (CML derivative) and use
OBGenericData to store the extra information from Avogadro. As for
settings etc, those can be stored by the program using the library. We
will need to add ::saveSettings(QSettings settings) function to the
Engine template at some point.
== Colors, Color Schemes and Materials ==
So here is how i would suggest implementing Colors, Color Schemes and
Materials from a code point of view. You pick a material (instance of
the Material class explained below) and apply the material for a given
color (rgba). ColorSchemes are designed to give you a Color (instance
of the Color class containing rgba) based on a primitive / selection /
text. This way an engine will have the option to select the material
and a color scheme. The engine would then take the following steps; get
a pointer to the instance of Material it should use, then for the
current primitive get an instance of Color from the ColorScheme
instance, draw the primitive.
I believe this benefits for a few different reasons. First, if you want
to have certain atoms in one material and certain atoms in another, you
simply duplicate the engine and have each engine only render a subset of
the atoms. The other ideas that I have though about is making
ColorScheme include the material and/or have material also be based off
the primitive, but from a user standpoint, am i going to really want to
go through and setup materials for each element? Probably not. From my
weak chemistry background, it doesn’t seem like you’re ever going to
want a MaterialScheme (material based on primitive). But maybe I am
wrong? This part needs some input from a chemist. I think the idea of
wanting different materials based on primitive is easy enough for the
few users that will want it by simply creating various engines and
setting them to different materials, rather than using a material
scheme. Especially since they can select by smiles.
=== Material ===
The current “”“Color”“” class is actually a “”“Material”“” class.
Material should be a dynamic class which can setup the various OpenGL
properties for rendering. It’s members would represent the various
parameters which you can set for an OpenGL material. Although, we
should provide some set of “preset” materials somehow, simply a static
function which returns lists of Materials would be sufficient, then
allow duplication (copy operator) of materials already instantiated.
Then, we add a class MaterialGroup which an application shares and
gives plugins and applications using libavogadro a common source of
possible materials which they can use when drawing. We could allow
these materials to be copied and modified by the user (through the GUI)
or by the application working with libavogadro and this way we have a
common way for the engines to paint. The Material class should have a
function(s):
- void ::apply(Color &color,
Material::Lighting lighting = Material::LightingEnabled); - Material ::operator=(Material &other);
Note: I do not believe it’s needed to do subclassing here, most
Materials will have to perform the same procedures, ie. they share the
same code but just different properties. If this is not the case
someone correct me. Also, i don’t think it’s necessary to have
materials changed based off primitives as stated above.
=== Color ===
The “”“Color”“” class should actually be almost a struct which allows
you to set the rgba of a color. It should be simple.
=== ColorScheme ===
The ColorScheme class should be a template class whose subclasses return
instances of Color. We would have a ColorSchemeGroup which you can
add instances of ColorScheme to and manage them (and be shared between
engines). Each color scheme would have a
::settingsWidget just like the engines and tools do. Thus,
we would have function(s):
- Color ::primitiveColor(Primitive *p) = 0;
- Color ::selectionColor() = 0;
- Color ::textColor() = 0;
- QWidget * ::settingsWidget() = 0;
There are considerations to be made with this class; most notably
depending on the type of color scheme, we benefit from using subclasses
and making ColorScheme a template class. As example is for
ElementColorScheme where the function to do primitiveColor() is based
off OpenBabel::etab and different code from say a class like
UserColorScheme which has a lookup table for each element (this same
functionality could also be built into ElementColorScheme). or even say
UserOddNumberColorScheme which is specialized so that user can say what
colors are odd numbers and what colors are not odd. or say
RadiusColorScheme where colors are determined by the radius of the
atoms. The “internal” functionality between different schemes could and
will be different from scheme to scheme. It is not as simple as
Material where we know exactly what knobs we can turn.
Let me know what you think. Out.
–
Donald Ephraim Curtis