face.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1998-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Tue Dec  1 08:00:00 1998
00010 // commit: $Id: face.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/visx/face.cc $
00012 //
00013 // This file is part of GroovX.
00014 //   [http://ilab.usc.edu/rjpeters/groovx/]
00015 //
00016 // GroovX is free software; you can redistribute it and/or modify it
00017 // under the terms of the GNU General Public License as published by
00018 // the Free Software Foundation; either version 2 of the License, or
00019 // (at your option) any later version.
00020 //
00021 // GroovX is distributed in the hope that it will be useful, but
00022 // WITHOUT ANY WARRANTY; without even the implied warranty of
00023 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024 // General Public License for more details.
00025 //
00026 // You should have received a copy of the GNU General Public License
00027 // along with GroovX; if not, write to the Free Software Foundation,
00028 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00029 //
00031 
00032 #ifndef GROOVX_VISX_FACE_CC_UTC20050626084016_DEFINED
00033 #define GROOVX_VISX_FACE_CC_UTC20050626084016_DEFINED
00034 
00035 #include "visx/face.h"
00036 
00037 #include "geom/vec3.h"
00038 
00039 #include "gfx/bbox.h"
00040 #include "gfx/canvas.h"
00041 
00042 #include "io/ioproxy.h"
00043 #include "io/reader.h"
00044 #include "io/writer.h"
00045 
00046 #include "rutz/algo.h"
00047 #include "rutz/fstring.h"
00048 
00049 #include "rutz/trace.h"
00050 #include "rutz/debug.h"
00051 GVX_DBG_REGISTER
00052 
00053 using geom::vec2d;
00054 using geom::vec3d;
00055 
00057 //
00058 // File scope data
00059 //
00061 
00062 namespace
00063 {
00064   const io::version_id FACE_SVID = 2;
00065 
00066   const double theirNose_x = 0.0;
00067   const double theirMouth_x[2] = {-0.2, 0.2};
00068 
00069   const int OUTLINE_PART_MASK   = 1 << 0;
00070   const int EYES_PART_MASK      = 1 << 1;
00071   const int NOSE_PART_MASK      = 1 << 2;
00072   const int MOUTH_PART_MASK     = 1 << 3;
00073 }
00074 
00076 //
00077 // Face member functions
00078 //
00080 
00082 // Creators
00084 
00085 const FieldMap& Face::classFields()
00086 {
00087   static const Field FIELD_ARRAY[] =
00088   {
00089     Field("category", &Face::itsFaceCategory, 0, 0, 10, 1, Field::NEW_GROUP),
00090     Field("eyeHeight", &Face::itsEyeHeight, 0.6, -1.2, 1.2, 0.01),
00091     Field("eyeDistance", &Face::itsEyeDistance, 0.4, 0.0, 1.8, 0.01),
00092     Field("noseLength", &Face::itsNoseLength, 0.4, -0.0, 3.0, 0.01),
00093     Field("mouthHeight", &Face::itsMouthHeight, 0.8, -1.2, 1.2, 0.01),
00094     Field("partsMask", &Face::itsPartsMask, 0, 0, 15, 1, Field::TRANSIENT),
00095     Field("isFilled", &Face::isItFilled, false, false, true, true,
00096           Field::TRANSIENT | Field::BOOLEAN)
00097   };
00098 
00099   static FieldMap FACE_FIELDS(FIELD_ARRAY, &GxShapeKit::classFields());
00100 
00101   return FACE_FIELDS;
00102 }
00103 
00104 Face* Face::make()
00105 {
00106 GVX_TRACE("Face::make");
00107   return new Face;
00108 }
00109 
00110 Face::Face(double eh, double es, double nl, double mh, int categ) :
00111   itsFaceCategory(categ),
00112   itsEyeHeight(eh),
00113   itsEyeDistance(es),
00114   itsNoseLength(nl),
00115   itsMouthHeight(mh),
00116   itsPartsMask(0),
00117   isItFilled(false)
00118 {
00119 GVX_TRACE("Face::Face");
00120 
00121   setFieldMap(Face::classFields());
00122 }
00123 
00124 Face::~Face() throw()
00125 {
00126 GVX_TRACE("Face::~Face");
00127   // nothing to do
00128 }
00129 
00130 io::version_id Face::class_version_id() const
00131 {
00132 GVX_TRACE("Face::class_version_id");
00133   return FACE_SVID;
00134 }
00135 
00136 void Face::read_from(io::reader& reader)
00137 {
00138 GVX_TRACE("Face::read_from");
00139 
00140   reader.ensure_version_id("Face", 2,
00141                            "Try cvs tag xml_conversion_20040526",
00142                            SRC_POS);
00143 
00144   readFieldsFrom(reader, classFields());
00145 
00146   reader.read_base_class("GxShapeKit", io::make_proxy<GxShapeKit>(this));
00147 }
00148 
00149 void Face::write_to(io::writer& writer) const
00150 {
00151 GVX_TRACE("Face::write_to");
00152 
00153   writer.ensure_output_version_id("Face", FACE_SVID, 2,
00154                               "Try groovx0.8a4", SRC_POS);
00155 
00156   writeFieldsTo(writer, classFields(), FACE_SVID);
00157 
00158   writer.write_base_class("GxShapeKit", io::make_const_proxy<GxShapeKit>(this));
00159 }
00160 
00162 // Actions
00164 
00165 void Face::grRender(Gfx::Canvas& canvas) const
00166 {
00167 GVX_TRACE("Face::grRender");
00168 
00169   //
00170   // Drawing commands begin here...
00171   //
00172 
00173   Gfx::AttribSaver attribSaver(canvas);
00174 
00175   canvas.enableAntialiasing();
00176 
00177   //
00178   // Draw face outline.
00179   //
00180 
00181   if ( !(itsPartsMask & OUTLINE_PART_MASK) )
00182     {
00183       // These parameters control the generation of the Bezier curve for
00184       // the face outline.
00185       const int num_subdivisions = 30;
00186       const int nctrlsets = 2;
00187       const double* const ctrlpnts = getCtrlPnts();
00188 
00189       for (int i = 0; i < nctrlsets; ++i)
00190         {
00191           if (isItFilled)
00192             {
00193               canvas.drawBezierFill4(vec3d(0.0, 0.0, 0.0),
00194                                      vec3d(ctrlpnts+i*12+0),
00195                                      vec3d(ctrlpnts+i*12+3),
00196                                      vec3d(ctrlpnts+i*12+6),
00197                                      vec3d(ctrlpnts+i*12+9),
00198                                      num_subdivisions);
00199             }
00200           else
00201             {
00202               canvas.drawBezier4(vec3d(ctrlpnts+i*12+0),
00203                                  vec3d(ctrlpnts+i*12+3),
00204                                  vec3d(ctrlpnts+i*12+6),
00205                                  vec3d(ctrlpnts+i*12+9),
00206                                  num_subdivisions);
00207             }
00208         }
00209     }
00210 
00211   {
00212     Gfx::MatrixSaver msaver(canvas);
00213     Gfx::AttribSaver asaver(canvas);
00214 
00215     if (isItFilled)
00216       canvas.swapForeBack();
00217 
00218     canvas.translate(vec3d(0.0, getVertOffset(), 0.0));
00219 
00220     //
00221     // Set up for drawing eyes.
00222     //
00223 
00224     // Generate the eyeball scales on the basis of the eye aspect. The
00225     // eye aspect should range from 0.0 to 1.0 to control the eyeball
00226     // x and y scales from 0.1 to 0.185. The x and y scales are always
00227     // at opposite points within this range.
00228     const double aspect = getEyeAspect();
00229 
00230     const vec3d eyeball_scale(0.1*aspect     + 0.185*(1-aspect),
00231                               0.1*(1-aspect) + 0.185*aspect,
00232                               1.0);
00233 
00234     // The absolute scale of the pupil.
00235     const vec3d pupil_scale_abs(0.07, 0.07, 1.0);
00236 
00237     // The scale of the pupil relative to the eyeball scale. These
00238     // values are computed since it is more efficient in the drawing
00239     // routine to do an additional scale for the pupils after having
00240     // drawn the eyeballs, rather than to pop the modelview matrix
00241     // after the eyeballs and push a new matrix for the pupils. But,
00242     // maybe this is the sort of optimization that OpenGL would make
00243     // on its own in a display list.
00244     const vec3d pupil_scale(pupil_scale_abs/eyeball_scale);
00245 
00246     // Calculate the x position for the eyes
00247     const double eye_x = rutz::abs(itsEyeDistance)/2.0;
00248 
00249     // Parameters for the circles for the eyeballs and the pupils.
00250     const int num_slices = 20;
00251     const int num_loops = 1;
00252     const double outer_radius = 0.5;
00253 
00254     // Draw eyes.
00255     if ( !(itsPartsMask & EYES_PART_MASK) )
00256       {
00257         for (int eye_pos = -1; eye_pos < 2; eye_pos += 2)
00258           {
00259             Gfx::MatrixSaver eyesaver(canvas);
00260 
00261             canvas.translate(vec3d(eye_pos * eye_x, itsEyeHeight, 0.0));
00262             canvas.scale(eyeball_scale);
00263 
00264             canvas.drawCircle(0.0, outer_radius, isItFilled,
00265                               num_slices, num_loops);
00266 
00267             canvas.scale(pupil_scale);
00268 
00269             {
00270               Gfx::AttribSaver asaver(canvas);
00271               if (isItFilled)
00272                 canvas.swapForeBack();
00273 
00274               canvas.drawCircle(0.0, outer_radius, isItFilled,
00275                                 num_slices, num_loops);
00276             }
00277           }
00278       }
00279 
00280     //
00281     // Draw nose and mouth.
00282     //
00283 
00284     // Calculate the positions for the top and bottom of the nose
00285     // bottom y always <= 0.0
00286     // top y always >= 0.0
00287     const vec2d nose_bottom(theirNose_x, -rutz::abs(itsNoseLength)/2.0);
00288     const vec2d nose_top(theirNose_x, -nose_bottom.y());
00289 
00290     {
00291       Gfx::LinesBlock block(canvas);
00292 
00293       if ( !(itsPartsMask & MOUTH_PART_MASK) )
00294         {
00295           canvas.vertex2(vec2d(theirMouth_x[0], itsMouthHeight));
00296           canvas.vertex2(vec2d(theirMouth_x[1], itsMouthHeight));
00297         }
00298 
00299       if ( !(itsPartsMask & NOSE_PART_MASK) )
00300         {
00301           canvas.vertex2(nose_bottom);
00302           canvas.vertex2(nose_top);
00303         }
00304     }
00305   }
00306 }
00307 
00309 // Accessors
00311 
00312 void Face::grGetBoundingBox(Gfx::Bbox& bbox) const
00313 {
00314 GVX_TRACE("Face::grGetBoundingBox");
00315 
00316   bbox.vertex2(vec2d(-0.7, 0.2 + 0.75*(-1.7-0.2)));
00317   bbox.vertex2(vec2d(+0.7, 0.2 + 0.75*(+1.4-0.2)));
00318 }
00319 
00320 int Face::category() const
00321 {
00322 GVX_TRACE("Face::category");
00323   return itsFaceCategory;
00324 }
00325 
00326 void Face::setCategory(int val)
00327 {
00328 GVX_TRACE("Face::setCategory");
00329   itsFaceCategory = val;
00330 }
00331 
00332 const double* Face::getCtrlPnts() const
00333 {
00334 GVX_TRACE("Face::getCtrlPnts");
00335   static const double ctrlpnts[] =
00336   {
00337     -.7, 0.2, 0.0, // first 4 control points
00338     -.7, 1.4, 0.0,
00339     .7, 1.4, 0.0,
00340     .7, 0.2, 0.0,
00341     .7, 0.2, 0.0, // second 4 control points
00342     .6, -1.7, 0.0,
00343     -.6, -1.7, 0.0,
00344     -.7, 0.2, 0.0
00345   };
00346   return ctrlpnts;
00347 }
00348 
00349 double Face::getEyeAspect() const
00350 {
00351 GVX_TRACE("Face::getEyeAspect");
00352   return 0.0;
00353 }
00354 
00355 double Face::getVertOffset() const
00356 {
00357 GVX_TRACE("Face::getVertOffset");
00358   return 0.0;
00359 }
00360 
00361 static const char __attribute__((used)) vcid_groovx_visx_face_cc_utc20050626084016[] = "$Id: face.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00362 #endif // !GROOVX_VISX_FACE_CC_UTC20050626084016_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:42 2008 by Doxygen version 1.5.5.