obj-material.cpp

Go to the documentation of this file.
00001 /*
00002  * obj-material.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Material handling for OBJ objects.  See obj-material.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "obj-material.h"               // always include our own header first
00036 
00037 #include "common/wave_ex.h"
00038 #include "perf/perf.h"
00039 #include "util/file.h"
00040 #include "util/parsing.h"
00041 #include "wave-glut/texture.h"
00042 
00043 
00044 namespace obj {
00045 
00046 
00047 static const eParseBehavior s_parseFlags                = eParse_Strip;
00048 
00049 
00050 
00051 ////////////////////////////////////////////////////////////////////////////////
00052 //
00053 //      static helper methods
00054 //
00055 ////////////////////////////////////////////////////////////////////////////////
00056 
00057 
00058 static void
00059 setMaterial
00060 (
00061 IN int flag,
00062 IN const glut::fcolor_t& c
00063 )
00064 throw()
00065 {
00066         float val[] = { c.red, c.green, c.blue, c.alpha };
00067         glMaterialfv(GL_FRONT_AND_BACK, flag, val);
00068 }
00069 
00070 
00071 
00072 static glut::fcolor_t
00073 parseColor
00074 (
00075 IN const char * p
00076 )
00077 {
00078         ASSERT(p, "null");
00079 
00080         const char * orig = p;
00081         glut::fcolor_t c;
00082         int n = readFloatsFromString(p, 3, &c.red);
00083         ASSERT_THROW(3 == n, "Incomplete color: " << orig);
00084 
00085         return c;
00086 }
00087 
00088 
00089 
00090 ////////////////////////////////////////////////////////////////////////////////
00091 //
00092 //      OBJMaterial: object that implements the glut::Material interface for
00093 //              Open Asset Import library materials.
00094 //
00095 ////////////////////////////////////////////////////////////////////////////////
00096 
00097 class OBJMaterial : public glut::Material {
00098 public:
00099         // constructor, destructor ---------------------------------------------
00100         OBJMaterial(void) throw(); 
00101         ~OBJMaterial(void) throw() { }
00102 
00103         // public class methods ------------------------------------------------
00104         void parseLine(IN const char * keyword,
00105                                 IN const char * line);
00106 
00107         // glut::Material class interface methods ------------------------------
00108         bool hasTexture(void) const throw() { return (0 != m_textureId); }
00109         void prepare(void);
00110         void cleanup(void) throw();
00111 
00112 private:
00113         // private typedefs ----------------------------------------------------
00114 
00115         // private data members ------------------------------------------------
00116         int                     m_textureId;
00117         int                     m_twosided;
00118         glut::fcolor_t          m_colorDiffuse;
00119         glut::fcolor_t          m_colorAmbient;
00120         glut::fcolor_t          m_colorSpecular;
00121         glut::fcolor_t          m_colorEmissive;
00122         float                   m_shininess;
00123         int                     m_oldPolyMode[2];
00124         int                     m_oldCull;
00125 };
00126 
00127 
00128 
00129 OBJMaterial::OBJMaterial
00130 (
00131 void
00132 )
00133 throw()
00134 {
00135         m_textureId = 0;
00136         m_twosided = 0;
00137         m_shininess = 10.0;
00138 }
00139 
00140 
00141 
00142 void
00143 OBJMaterial::parseLine
00144 (
00145 IN const char * keyword,        // first token on this line in mtl file
00146 IN const char * line            // actually, the remainder of the line
00147 )
00148 {
00149         ASSERT(keyword, "null");
00150         ASSERT(line, "null");
00151 
00152         // switch based on keyword--most common first!
00153         if (!strcmp("Kd", keyword)) {
00154                 m_colorDiffuse = parseColor(line);
00155         } else {
00156                 DPRINTF("Ignoring unknown material keyword: '%s'", keyword);
00157                 DPRINTF("  %s %s", keyword, line);
00158         }
00159 }
00160 
00161 
00162 
00163 ////////////////////////////////////////////////////////////////////////////////
00164 //
00165 //      OBJMaterial -- glut::Material class interface methods
00166 //
00167 ////////////////////////////////////////////////////////////////////////////////
00168 
00169 void
00170 OBJMaterial::prepare
00171 (
00172 void
00173 )
00174 {
00175         // set all the colors
00176 //      setMaterial(GL_AMBIENT, m_colorAmbient);
00177         setMaterial(GL_DIFFUSE, m_colorDiffuse);
00178 //      setMaterial(GL_SPECULAR, m_colorSpecular);
00179 //      setMaterial(GL_EMISSION, m_colorEmissive);
00180 
00181         // set shininess
00182         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m_shininess);
00183 
00184         // bind texture
00185         if (m_textureId) {
00186                 glEnable(GL_TEXTURE_2D);
00187                 glBindTexture(GL_TEXTURE_2D, m_textureId);
00188         }
00189 
00190         // turn off culling?
00191         if (m_twosided) {
00192                 // save current polygon mode
00193                 glGetIntegerv(GL_POLYGON_MODE, m_oldPolyMode);
00194                 glPolygonMode(GL_BACK, m_oldPolyMode[0]);       // set back == front
00195                 glGetIntegerv(GL_CULL_FACE, &m_oldCull);
00196                 glDisable(GL_CULL_FACE);
00197         }
00198 }
00199 
00200 
00201 
00202 void
00203 OBJMaterial::cleanup
00204 (
00205 void
00206 )
00207 throw()
00208 {
00209         if (m_textureId) {
00210                 glDisable(GL_TEXTURE_2D);
00211         }
00212         if (m_twosided) {
00213                 glPolygonMode(GL_FRONT, m_oldPolyMode[0]);
00214                 glPolygonMode(GL_BACK, m_oldPolyMode[1]);
00215                 if (m_oldCull) {
00216                         glEnable(GL_CULL_FACE);
00217                 }
00218         }
00219 }
00220 
00221 
00222 
00223 ////////////////////////////////////////////////////////////////////////////////
00224 //
00225 //      OBJMaterial -- private helper methods
00226 //
00227 ////////////////////////////////////////////////////////////////////////////////
00228 
00229 
00230 
00231 ////////////////////////////////////////////////////////////////////////////////
00232 //
00233 //      public API
00234 //
00235 ////////////////////////////////////////////////////////////////////////////////
00236 
00237 map_mtl_t
00238 parseOBJMaterials
00239 (
00240 IN nstream::Stream * stream
00241 )
00242 {
00243         ASSERT_THROW(stream->good(), "Bad stream?");
00244 
00245         map_mtl_t materials;
00246 
00247         // parse materials!
00248         std::string line, keyword;
00249         smart_ptr<OBJMaterial> curr;    // current material
00250         while (!stream->eof()) {
00251                 line = getNextLineFromStream(*stream, s_parseFlags);
00252 
00253                 const char * p = line.c_str();
00254 
00255                 p = getNextTokenFromString(p, keyword, s_parseFlags);
00256                 if ("" == keyword) {
00257                         continue;       // skip empty lines
00258                 }
00259 
00260                 // check keyword
00261                 if ("newmtl" == keyword) {
00262                         std::string name;
00263                         getNextTokenFromString(p, name, s_parseFlags);
00264                         ASSERT_THROW("" != name, "Bad material name in file!");
00265 
00266                         curr = new OBJMaterial;
00267                         ASSERT(curr, "out of memory");
00268 
00269                         materials[name] = curr;
00270                 } else {
00271                         // unknown keyword!  Pass on to material
00272                         if (!curr) {
00273                                 WAVE_EX(wex);
00274                                 wex << "Encountered keyword before newmtl?  ";
00275                                 wex << "line: " << line;
00276                         }
00277                         curr->parseLine(keyword.c_str(), p);
00278                 }
00279         }
00280 
00281         // all done!
00282         return materials;
00283 }
00284 
00285 
00286 
00287 };      // obj namespace
00288