2 // Copyright (C) 2007 by Martin Moracek
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #ifdef BUILD_CG_PREPROCESSOR
33 # include <boost/wave.hpp>
34 # include <boost/wave/cpplexer/cpp_lex_token.hpp>
35 # include <boost/wave/cpplexer/cpp_lex_iterator.hpp>
36 # include <boost/wave/util/iteration_context.hpp>
37 #endif /* BUILD_CG_PREPROCESSOR */
39 #include "exception.h"
41 #include "vfs/logfile.h"
42 #include "vfs/fstream.h"
43 #include "vfs/interface.h"
45 #include "renderer/effect.h"
46 #include "renderer/texture.h"
47 #include "renderer/renderer.h"
49 #include "cg_effect.h"
50 #include "cg_renderer.h"
52 #include "gl_texture.h"
54 #include "memory/mmgr.h"
56 #ifdef BUILD_CG_PREPROCESSOR
57 // preprocessor input policy
60 namespace iteration_context_policies
{
62 struct vfs_file_to_string
{
63 template <typename IterContext
>
66 template <typename PositionT
>
67 static void init_iterators(IterContext
&iter_ctx
,
68 PositionT
const &act_pos
, language_support language
)
70 typedef typename
IterContext::iterator_type iterator_type
;
73 tre::FileIStream
file(iter_ctx
.filename
.c_str());
75 BOOST_WAVE_THROW_CTX(iter_ctx
.ctx
, preprocess_exception
,
76 bad_include_file
, iter_ctx
.filename
.c_str(), act_pos
);
79 file
.unsetf(std::ios::skipws
);
81 iter_ctx
.instring
.assign(
82 std::istreambuf_iterator
<char>(file
.rdbuf()),
83 std::istreambuf_iterator
<char>());
85 iter_ctx
.first
= iterator_type(iter_ctx
.instring
.begin(),
86 iter_ctx
.instring
.end(), PositionT(iter_ctx
.filename
),
88 iter_ctx
.last
= iterator_type();
98 #endif /* BUILD_CG_PREPROCESSOR */
102 EffectVars::EffectVars()
106 EffectVars::~EffectVars()
110 void EffectVars::SetTexture(const std::string
& name
, const std::string
& var
)
112 TexturePtr tex
= Texture::Factory().CreateInstance(var
);
113 SetTexture(name
, tex
);
116 void EffectVars::SetTexture(const std::string
& name
, const TexturePtr
& var
)
118 SVarVector::iterator pos
= std::lower_bound(
119 samplers
.begin(), samplers
.end(), name
);
121 if(pos
== samplers
.end() || pos
->first
!= name
) {
122 samplers
.insert(pos
, std::make_pair(name
, var
));
128 CgEffect::EffectParameter::EffectParameter(const std::string
& n
,
129 CGparameter p
, EffectVarType t
) : name(n
), param(p
), type(t
)
131 // memset(&var, 0, sizeof(var));
134 const EffectPtr
EffectFactory::CreateInstance(const std::string
& name
)
136 EffectMap::iterator pos
= map_
.find(name
);
138 if(pos
!= map_
.end() && !pos
->second
.expired())
139 return pos
->second
.lock();
141 if(pos
== map_
.end())
142 pos
= map_
.insert(pos
, std::make_pair(name
, EffectPtr()));
144 DEBUG_ASSERT(pos
!= map_
.end());
148 // need to pass the name stored in the element
149 res
= EffectPtr(new CgEffect(pos
->first
));
151 vLog
<< ok("Cg") << "Effect loaded successfully ("
152 << name
<< ")." << std::endl
;
153 } catch(Exception
& exc
) {
154 vLog
<< err("Cg") << "Unable to load effect (" + name
+ ").\nReason: "
155 << exc
.what() << std::endl
;
161 CgEffect::CgEffect(const std::string
& filename
)
163 #ifdef BUILD_CG_PREPROCESSOR
164 // read the while effect file into memory
165 FileIStream
file(filename
);
167 throw(Exception("Error opening file."));
169 std::string
input(std::istreambuf_iterator
<char>(file
.rdbuf()),
170 std::istreambuf_iterator
<char>());
172 // preprocess the cgfx file using Wave preprocessor library
173 typedef boost::wave::cpplexer::lex_iterator
<
174 boost::wave::cpplexer::lex_token
<> > lex_iterator_type
;
175 typedef boost::wave::iteration_context_policies::vfs_file_to_string
177 typedef boost::wave::context
<std::string::iterator
,
178 lex_iterator_type
, input_policy_type
> context_type
;
180 context_type
ctx(input
.begin(), input
.end(), filename
.c_str());
182 // ctx.add_include_path("...");
183 // ctx.add_macro_definition(...);
185 std::stringstream ss
;
187 // iterate over the tokens
188 for(context_type::iterator_type itr
= ctx
.begin();
189 itr
!= ctx
.end(); ++itr
) {
190 ss
<< (*itr
).get_value();
193 effect_
= cgCreateEffect(static_cast<CgRenderer
&>(sRenderer()
194 ).GetCgContext(), ss
.str().c_str(), NULL
);
195 #else /* BUILD_CG_PREPROCESSOR */
196 effect_
= cgCreateEffectFromFile(static_cast<CgRenderer
&>(sRenderer()
197 ).GetCgContext(), sVfs().TranslatePath(filename
).c_str(), NULL
);
198 #endif /* BUILD_CG_PREPROCESSOR */
201 const char * str
= cgGetLastListing(
202 static_cast<CgRenderer
&>(sRenderer()).GetCgContext());
203 throw(Exception(str
? str
: "Error reading from file?"));
206 // find the first available technique
207 technique_
= cgGetFirstTechnique(effect_
);
208 while(technique_
&& cgValidateTechnique(technique_
) == CG_FALSE
) {
209 vLog
<< warn("Cg") << "Technique " << cgGetTechniqueName(technique_
)
210 << " did not validate. Skipping." << std::endl
;
211 technique_
= cgGetNextTechnique(technique_
);
214 vLog
<< info("Cg") << "Using technique " << cgGetTechniqueName(technique_
)
217 throw(Exception("No valid technique."));
220 // enumerate effect parameters
221 CGparameter par
= cgGetFirstEffectParameter(effect_
);
223 const char * sem
= cgGetParameterSemantic(par
);
227 if(strcasecmp(sem
, "Time") == 0) {
230 CGannotation ann
= cgGetNamedParameterAnnotation(par
, "type");
232 if(!ann
|| !(str
= cgGetStringAnnotationValue(ann
)) ||
233 strcmp(str
, "system") != 0) {
234 internals_
.push_back(std::make_pair(itTime
, par
));
236 internals_
.push_back(std::make_pair(itSysTime
, par
));
238 } else if(strcasecmp(sem
, "ModelViewProjection") == 0) {
239 CheckMatrixVar(itMVPMatrix
, par
);
240 } else if(strcasecmp(sem
, "ModelView") == 0) {
241 CheckMatrixVar(itMVMatrix
, par
);
242 } else if(strcasecmp(sem
, "Projection") == 0) {
243 CheckMatrixVar(itPMatrix
, par
);
244 } else if(strcasecmp(sem
, "Texture") == 0) {
245 CheckMatrixVar(itTMatrix
, par
);
249 const char * name
= cgGetParameterName(par
);
251 switch(cgGetParameterType(par
)) {
258 params_
.push_back(EffectParameter(name
, par
, vtFloat1
));
263 params_
.push_back(EffectParameter(name
, par
, vtFloat2
));
268 params_
.push_back(EffectParameter(name
, par
, vtFloat3
));
273 params_
.push_back(EffectParameter(name
, par
, vtFloat4
));
279 params_
.push_back(EffectParameter(name
, par
, vtInt1
));
283 params_
.push_back(EffectParameter(name
, par
, vtInt2
));
287 params_
.push_back(EffectParameter(name
, par
, vtInt3
));
291 params_
.push_back(EffectParameter(name
, par
, vtInt4
));
298 params_
.push_back(EffectParameter(name
, par
, vtTexture
));
305 par
= cgGetNextParameter(par
);
307 std::sort(internals_
.begin(), internals_
.end());
308 std::sort(params_
.begin(), params_
.end());
311 CgEffect::~CgEffect()
313 cgDestroyEffect(effect_
);
316 void CgEffect::SetParameters(const EffectVars
& vars
) const
319 for(FVarVector::const_iterator itr
= vars
.fvars
.begin();
320 itr
!= vars
.fvars
.end(); ++itr
) {
321 ChangeFloatVariable(itr
->first
, itr
->second
);
325 for(IVarVector::const_iterator itr
= vars
.ivars
.begin();
326 itr
!= vars
.ivars
.end(); ++itr
) {
327 ChangeIntVariable(itr
->first
, itr
->second
);
331 for(SVarVector::const_iterator itr
= vars
.samplers
.begin();
332 itr
!= vars
.samplers
.end(); ++itr
) {
333 ChangeSamplerVariable(itr
->first
, itr
->second
);
337 void CgEffect::ChangeFloatVariable
338 (const std::string
& name
, const FxFVar
& value
) const
340 ParamVector::const_iterator var
= std::lower_bound(
341 params_
.begin(), params_
.end(), name
);
343 if(var
== params_
.end() || var
->name
!= name
)
346 if(var
->type
>= vtFloat1
&& var
->type
<= vtFloat4
)
347 cgSetParameterValuefr(var
->param
, 4, value
.data());
350 void CgEffect::ChangeIntVariable
351 (const std::string
& name
, const FxIVar
& value
) const
353 ParamVector::const_iterator var
= std::lower_bound(
354 params_
.begin(), params_
.end(), name
);
356 if(var
== params_
.end() || var
->name
!= name
)
359 if(var
->type
>= vtInt1
&& var
->type
<= vtInt4
)
360 cgSetParameterValueir(var
->param
, 4, value
.data());
363 void CgEffect::ChangeSamplerVariable
364 (const std::string
& name
, const TexturePtr
& value
) const
366 ParamVector::const_iterator var
= std::lower_bound(
367 params_
.begin(), params_
.end(), name
);
369 if(var
== params_
.end() || var
->name
!= name
)
372 if(var
->type
== vtTexture
)
373 cgGLSetupSampler(var
->param
,
374 static_cast<GLTexture
*>(value
.get())->GetHandle());
377 void CgEffect::CheckMatrixVar(InternalsType base
, CGparameter par
)
379 bool inv
= false, trans
= false;
384 ann
= cgGetNamedParameterAnnotation(par
, "inverse");
385 if(ann
&& (vals
= cgGetBoolAnnotationValues(ann
, &n
)) && n
> 0)
388 ann
= cgGetNamedParameterAnnotation(par
, "transpose");
389 if(ann
&& (vals
= cgGetBoolAnnotationValues(ann
, &n
)) && n
> 0)
393 internals_
.push_back(std::make_pair(
394 static_cast<InternalsType
>(base
+ 3), par
));
396 internals_
.push_back(std::make_pair(
397 static_cast<InternalsType
>(base
+ 1), par
));
399 internals_
.push_back(std::make_pair(
400 static_cast<InternalsType
>(base
+ 2), par
));
402 internals_
.push_back(std::make_pair(base
, par
));