00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
00078
00080
00082
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
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
00164
00165 void Face::grRender(Gfx::Canvas& canvas) const
00166 {
00167 GVX_TRACE("Face::grRender");
00168
00169
00170
00171
00172
00173 Gfx::AttribSaver attribSaver(canvas);
00174
00175 canvas.enableAntialiasing();
00176
00177
00178
00179
00180
00181 if ( !(itsPartsMask & OUTLINE_PART_MASK) )
00182 {
00183
00184
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
00222
00223
00224
00225
00226
00227
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
00235 const vec3d pupil_scale_abs(0.07, 0.07, 1.0);
00236
00237
00238
00239
00240
00241
00242
00243
00244 const vec3d pupil_scale(pupil_scale_abs/eyeball_scale);
00245
00246
00247 const double eye_x = rutz::abs(itsEyeDistance)/2.0;
00248
00249
00250 const int num_slices = 20;
00251 const int num_loops = 1;
00252 const double outer_radius = 0.5;
00253
00254
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
00282
00283
00284
00285
00286
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
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,
00338 -.7, 1.4, 0.0,
00339 .7, 1.4, 0.0,
00340 .7, 0.2, 0.0,
00341 .7, 0.2, 0.0,
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