Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/util/Convert.h @ 1003

Last change on this file since 1003 was 1003, checked in by landauf, 18 years ago

hopefully solved the conversion problem :)

it's a lot of metaprogramming now but this reduces the risk getting unnecessary compiler errors:
if (convert(a, b))

return true;

else

return convertFallback(a, b);

if convert(a, b) is defined and always used you could still get an error if convertFallback(a, b) uses something (like stream << object) that isn't supported for a or b. but with some template tricks it's possible to not even consider using convertFallback(a, b) at compiletime and avoid the error as long as convert(a, b) is implemented.

util/Conver.h is now opened for curious coders ;)

File size: 23.1 KB
RevLine 
[961]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Benjamin Grauer
[1003]23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
[961]26 */
27
28/*!
29    @file Convert.h
30    @brief Definition and Implementation of the Convert class.
31*/
32
33#ifndef _Convert_H__
34#define _Convert_H__
35
36#include <string>
37#include <sstream>
38
39#include "UtilPrereqs.h"
40#include "Math.h"
41#include "SubString.h"
42#include "MultiTypeMath.h"
[1001]43
44
45//////////
46// Main //
47//////////
[1003]48
49// Enum to declare the wanted conversion preference in case of equal type-levels
[1001]50enum ConversionPreference
51{
[1003]52    CP_PreferToType,
53    CP_PreferFromType,
[1001]54};
55
56// Helper classes to determine the preferred partial template specialization
[1003]57class _ToType_   {};
58class _FromType_ {};
59class _Explicit_ {};
[1001]60
61
62// The default convert functions
[1003]63template <class FromType, class ToType, class Type>
64struct ConverterSpecialized
65{
66    enum { specialized = false };
67    static bool convert(ToType* output, const FromType& input)
68    { return false; }
69};
[1001]70
71
72// The default convert function if both types are the same
73template <class BothTypes>
[1003]74struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
[1001]75{
[1003]76    enum { specialized = true };
77    static bool convert(BothTypes* output, const BothTypes& input)
[1001]78    { (*output) = input; return true; }
[1003]79};
[1001]80
81
[1003]82// The possible levels
83#define __low__  0 // Everything that is or behaves like a primitive type (an can be converted with a typecast to every other low-level type)
84#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
85#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
[1001]86
[1003]87// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
88template <class T> struct ConverterLevel           { enum { level = __high__ }; };
89template <> struct ConverterLevel<std::string>     { enum { level = __mid__ }; };
90template <> struct ConverterLevel<orxonox::Radian> { enum { level = __mid__ }; };
91template <> struct ConverterLevel<orxonox::Degree> { enum { level = __mid__ }; };
92template <> struct ConverterLevel<int>             { enum { level = __low__ }; };
93template <> struct ConverterLevel<unsigned int>    { enum { level = __low__ }; };
94template <> struct ConverterLevel<char>            { enum { level = __low__ }; };
95template <> struct ConverterLevel<unsigned char>   { enum { level = __low__ }; };
96template <> struct ConverterLevel<short>           { enum { level = __low__ }; };
97template <> struct ConverterLevel<unsigned short>  { enum { level = __low__ }; };
98template <> struct ConverterLevel<long>            { enum { level = __low__ }; };
99template <> struct ConverterLevel<unsigned long>   { enum { level = __low__ }; };
100template <> struct ConverterLevel<float>           { enum { level = __low__ }; };
101template <> struct ConverterLevel<double>          { enum { level = __low__ }; };
102template <> struct ConverterLevel<long double>     { enum { level = __low__ }; };
103template <> struct ConverterLevel<bool>            { enum { level = __low__ }; };
[1001]104
105
[1003]106// Calculates the preference based on the levels of FromType and ToType
107template <int from, int to>
108struct ConverterPreference
109{
110    enum
[1001]111    {
[1003]112        // The maximum of both levels: element of {0, 1, 2}
113        // max 0: Both types are primitives or have a similar behaviour
114        // max 1: At least one type is not a primitive, but both can be put on a std::stream
115        // max 2: There is at least one generic type that needs specialized conversions
116        max = (from > to) ? from : to,
[1001]117
[1003]118        // The difference between both levels limited to +-1: element of {-1, 0, 1}
119        // diff -1: The FromType has higher level than the ToType
120        // diff  0: Both types have the same level
121        // diff  1: The ToType has higher level than the FromType
122        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
[1001]123    };
[1003]124};
[1001]125
126
[1003]127// The default conversion: This usually does nothing
128template <int max, class FromType, class ToType>
129struct ConverterDefault
130{
131    static bool convert(ToType* output, const FromType& input)
[1001]132    {
[1003]133        return false;
134    }
135};
136// The default conversion for primitives: A typecast (defined over two partial specialized templates to exclude all non-primitive types and classes)    template <int max, class FromType, class ToType>
137template <class FromType, class ToType>
138struct ConverterDefault<0, FromType, ToType>
139{
140    static bool convert(ToType* output, const FromType& input)
[1001]141    {
[1003]142        (*output) = (ToType)input;
143        return true;
144    }
145};
[1001]146
147
[1003]148// Converter: Converts input of FromType into output of ToType
149template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
150struct Converter
151{
152    static bool convert(ToType* output, const FromType& input)
[1001]153    {
[1003]154        return false;
155    }
156};
157// Converter: level{FromType} > level{ToType}
158template <int max, class FromType, class ToType, ConversionPreference pref>
159struct Converter<-1, max, FromType, ToType, pref>
160{   static bool convert(ToType* output, const FromType& input)
161    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
162// Converter: level{FromType} < level{ToType}
163template <int max, class FromType, class ToType, ConversionPreference pref>
164struct Converter<1, max, FromType, ToType, pref>
165{   static bool convert(ToType* output, const FromType& input)
166    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
167// Converter: level{FromType} = level{ToType}
168// CP_PreferToType
169template <int max, class FromType, class ToType>
170struct Converter<0, max, FromType, ToType, CP_PreferToType>
171{   static bool convert(ToType* output, const FromType& input)
172    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
173// CP_PreferFromType
174template <int max, class FromType, class ToType>
175struct Converter<0, max, FromType, ToType, CP_PreferFromType>
176{   static bool convert(ToType* output, const FromType& input)
177    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
[1001]178
179
[1003]180// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
181template <class FromType, class ToType>
182static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
183{
184    return (preference == CP_PreferToType) ?
185           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
186                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
187                     FromType,
188                     ToType,
189                     CP_PreferToType>::convert(output, input)
190         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
191                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
192                     FromType,
193                     ToType,
194                     CP_PreferFromType>::convert(output, input);
195}
[1001]196
197
198// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
199template<class FromType, class ToType>
[1003]200static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
[1001]201{
202    return convertValue(output, input, preference);
203}
204template<class FromType, class ToType>
[1003]205static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
[1001]206{
207    if (convertValue(output, input, preference))
208        return true;
209
210    (*output) = fallback;
211    return false;
212}
213
214// Helper function: Calls convertValue with and without default value and returns the converted value
215template<class FromType, class ToType>
[1003]216static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
[1001]217{
218    ToType output = ToType();
219    ConvertValue(&output, input, preference);
220    return output;
221}
222template<class FromType, class ToType>
[1003]223static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
[1001]224{
225    ToType output = fallback;
226    ConvertValue(&output, input, fallback, preference);
227    return output;
228}
[961]229
[1001]230/////////////////////
231// SPECIALISATIONS //
232/////////////////////
233
[1003]234/////////////
235// Samples //
236/////////////
[1001]237/*
[1003]238// convert everything to xyz
[1001]239template <class FromType>
[1003]240struct ConverterSpecialized<FromType, xyz, _ToType_>
[1001]241{
[1003]242    enum { specialized = true };
243    static bool convert(xyz* output, const FromType& input)
244    { return ...; }
245};
[1001]246
[1003]247// convert xyz to everything
[1001]248template <class ToType>
[1003]249struct ConverterSpecialized<xyz, ToType, _FromType_>
[1001]250{
[1003]251    enum { specialized = true };
252    static bool convert(ToType* output, const xyz& input)
253    { return ...; }
254};
[1001]255
[1003]256// convert abc to xyz
[1001]257template <>
[1003]258struct ConverterSpecialized<abc, xyz, _Explicit_>
[1001]259{
[1003]260    enum { specialized = true };
261    static bool convert(xyz* output, const abc& input)
262    { return ...; }
263};
[1001]264*/
265
266////////////
267// String //
268////////////
269
270// convert to string
271template <class FromType>
[1003]272struct ConverterSpecialized<FromType, std::string, _ToType_>
[1001]273{
[1003]274    enum { specialized = true };
275    static bool convert(std::string* output, const FromType& input)
[1001]276    {
[1003]277        std::ostringstream oss;
278        if (oss << input)
279        {
280            (*output) = oss.str();
281            return true;
282        }
283        else
284            return false;
[1001]285    }
[1003]286};
[1001]287
288// convert from string
289template <class ToType>
[1003]290struct ConverterSpecialized<std::string, ToType, _FromType_>
[1001]291{
[1003]292    enum { specialized = true };
293    static bool convert(ToType* output, const std::string& input)
294    {
295        std::istringstream iss(input);
296        if (iss >> (*output))
297            return true;
298        else
299            return false;
300    }
301};
[1001]302
303
304////////////////
305// MULTITYPES //
306////////////////
307
308// convert from MultiTypePrimitive
309template <class ToType>
[1003]310struct ConverterSpecialized<MultiTypePrimitive, ToType, _FromType_>
[1001]311{
[1003]312    enum { specialized = true };
313    static bool convert(ToType* output, const MultiTypePrimitive& input)
314    {
315        if (input.getType() == MT_void)
316            return ConvertValue(output, input.getVoid());
317        else if (input.getType() == MT_int)
318            return ConvertValue(output, input.getInt());
319        else if (input.getType() == MT_uint)
320            return ConvertValue(output, input.getUnsignedInt());
321        else if (input.getType() == MT_char)
322            return ConvertValue(output, input.getChar());
323        else if (input.getType() == MT_uchar)
324            return ConvertValue(output, input.getUnsignedChar());
325        else if (input.getType() == MT_short)
326            return ConvertValue(output, input.getShort());
327        else if (input.getType() == MT_ushort)
328            return ConvertValue(output, input.getUnsignedShort());
329        else if (input.getType() == MT_long)
330            return ConvertValue(output, input.getLong());
331        else if (input.getType() == MT_ulong)
332            return ConvertValue(output, input.getUnsignedLong());
333        else if (input.getType() == MT_float)
334            return ConvertValue(output, input.getFloat());
335        else if (input.getType() == MT_double)
336            return ConvertValue(output, input.getDouble());
337        else if (input.getType() == MT_longdouble)
338            return ConvertValue(output, input.getLongDouble());
339        else if (input.getType() == MT_bool)
340            return ConvertValue(output, input.getBool());
341        else
342            return false;
343    }
344};
[1001]345
346// convert from MultiTypeString
347template <class ToType>
[1003]348struct ConverterSpecialized<MultiTypeString, ToType, _FromType_>
[1001]349{
[1003]350    enum { specialized = true };
351    static bool convert(ToType* output, const MultiTypeString& input)
352    {
353        if (input.getType() == MT_constchar)
354            return ConvertValue(output, input.getConstChar());
355        else if (input.getType() == MT_string)
356            return ConvertValue(output, input.getString());
357        else
358            return ConvertValue(output, (MultiTypePrimitive)input);
359    }
360};
[1001]361
362// convert from MultiTypeMath
363template <class ToType>
[1003]364struct ConverterSpecialized<MultiTypeMath, ToType, _FromType_>
[1001]365{
[1003]366    enum { specialized = true };
367    static bool convert(ToType* output, const MultiTypeMath& input)
368    {
369        if (input.getType() == MT_vector2)
370            return ConvertValue(output, input.getVector2());
371        else if (input.getType() == MT_vector3)
372            return ConvertValue(output, input.getVector3());
373        else if (input.getType() == MT_quaternion)
374            return ConvertValue(output, input.getQuaternion());
375        else if (input.getType() == MT_colourvalue)
376            return ConvertValue(output, input.getColourValue());
377        else if (input.getType() == MT_radian)
378            return ConvertValue(output, input.getRadian());
379        else if (input.getType() == MT_degree)
380            return ConvertValue(output, input.getDegree());
381        else
382            return ConvertValue(output, (MultiTypeString)input);
383    }
384};
[1001]385
[961]386
387////////////////////
388// MATH TO STRING //
389////////////////////
[1001]390
391// Vector2 to std::string
392template <>
[1003]393struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
[1001]394{
[1003]395    enum { specialized = true };
396    static bool convert(std::string* output, const orxonox::Vector2& input)
[1001]397    {
[1003]398        std::ostringstream ostream;
399        if (ostream << input.x << "," << input.y)
400        {
401            (*output) = ostream.str();
402            return true;
403        }
404        return false;
[1001]405    }
[1003]406};
[1001]407
408// Vector3 to std::string
409template <>
[1003]410struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
[1001]411{
[1003]412    enum { specialized = true };
413    static bool convert(std::string* output, const orxonox::Vector3& input)
[1001]414    {
[1003]415        std::ostringstream ostream;
416        if (ostream << input.x << "," << input.y << "," << input.z)
417        {
418            (*output) = ostream.str();
419            return true;
420        }
421        return false;
[1001]422    }
[1003]423};
[1001]424
425// Vector4 to std::string
426template <>
[1003]427struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
[1001]428{
[1003]429    enum { specialized = true };
430    static bool convert(std::string* output, const orxonox::Vector4& input)
[1001]431    {
[1003]432        std::ostringstream ostream;
433        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
434        {
435            (*output) = ostream.str();
436            return true;
437        }
438        return false;
[1001]439    }
[1003]440};
441
[1001]442// Quaternion to std::string
443template <>
[1003]444struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
[1001]445{
[1003]446    enum { specialized = true };
447    static bool convert(std::string* output, const orxonox::Quaternion& input)
[1001]448    {
[1003]449        std::ostringstream ostream;
450        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
451        {
452            (*output) = ostream.str();
453            return true;
454        }
455        return false;
[1001]456    }
[1003]457};
458
[1001]459// ColourValue to std::string
460template <>
[1003]461struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
[1001]462{
[1003]463    enum { specialized = true };
464    static bool convert(std::string* output, const orxonox::ColourValue& input)
[1001]465    {
[1003]466        std::ostringstream ostream;
467        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
468        {
469            (*output) = ostream.str();
470            return true;
471        }
472        return false;
[1001]473    }
[1003]474};
[1001]475
476
[961]477////////////////////
478// STRING TO MATH //
479////////////////////
[1001]480
481// std::string to Vector2
482template <>
[1003]483struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
[1001]484{
[1003]485    enum { specialized = true };
486    static bool convert(orxonox::Vector2* output, const std::string& input)
[1001]487    {
[1003]488        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
489        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]490
[1003]491        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
492        if (tokens.size() >= 2)
493        {
494            if (!ConvertValue(&(output->x), tokens[0]))
495                return false;
496            if (!ConvertValue(&(output->y), tokens[1]))
497                return false;
498
499            return true;
500        }
501        return false;
[1001]502    }
[1003]503};
504
[1001]505// std::string to Vector3
506template <>
[1003]507struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
[1001]508{
[1003]509    enum { specialized = true };
510    static bool convert(orxonox::Vector3* output, const std::string& input)
[1001]511    {
[1003]512        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
513        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]514
[1003]515        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
516        if (tokens.size() >= 3)
517        {
518            if (!ConvertValue(&(output->x), tokens[0]))
519                return false;
520            if (!ConvertValue(&(output->y), tokens[1]))
521                return false;
522            if (!ConvertValue(&(output->z), tokens[2]))
523                return false;
524
525            return true;
526        }
527        return false;
[1001]528    }
[1003]529};
530
[1001]531// std::string to Vector4
532template <>
[1003]533struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
[1001]534{
[1003]535    enum { specialized = true };
536    static bool convert(orxonox::Vector4* output, const std::string& input)
[1001]537    {
[1003]538        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
539        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]540
[1003]541        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
542        if (tokens.size() >= 4)
543        {
544            if (!ConvertValue(&(output->x), tokens[0]))
545                return false;
546            if (!ConvertValue(&(output->y), tokens[1]))
547                return false;
548            if (!ConvertValue(&(output->z), tokens[2]))
549                return false;
550            if (!ConvertValue(&(output->w), tokens[3]))
551                return false;
552
553            return true;
554        }
555        return false;
[1001]556    }
[1003]557};
558
[1001]559// std::string to Quaternion
560template <>
[1003]561struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
[1001]562{
[1003]563    enum { specialized = true };
564    static bool convert(orxonox::Quaternion* output, const std::string& input)
[1001]565    {
[1003]566        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
567        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]568
[1003]569        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
570        if (tokens.size() >= 4)
571        {
572            if (!ConvertValue(&(output->w), tokens[0]))
573                return false;
574            if (!ConvertValue(&(output->x), tokens[1]))
575                return false;
576            if (!ConvertValue(&(output->y), tokens[2]))
577                return false;
578            if (!ConvertValue(&(output->z), tokens[3]))
579                return false;
580
581            return true;
582        }
583        return false;
[1001]584    }
[1003]585};
586
[1001]587// std::string to ColourValue
588template <>
[1003]589struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
[1001]590{
[1003]591    enum { specialized = true };
592    static bool convert(orxonox::ColourValue* output, const std::string& input)
[1001]593    {
[1003]594        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
595        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]596
[1003]597        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
598        if (tokens.size() >= 4)
599        {
600            if (!ConvertValue(&(output->r), tokens[0]))
601                return false;
602            if (!ConvertValue(&(output->g), tokens[1]))
603                return false;
604            if (!ConvertValue(&(output->b), tokens[2]))
605                return false;
606            if (!ConvertValue(&(output->a), tokens[3]))
607                return false;
608
609            return true;
610        }
611        return false;
[1001]612    }
613};
[961]614
615#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.