Initial commit, includes Lua with broken Luabind as a backup for branching purposes
[terrastrategy.git] / src / renderer / cg_effect.cpp
blob9acc9be8c931684517ee298b43c4036b3145c8dd
1 //
2 // Copyright (C) 2007 by Martin Moracek
3 //
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.
8 //
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
19 /**
20 * @file cg_effect.cpp
22 * Ble.
25 #include <GL/glew.h>
26 #include <Cg/cgGL.h>
28 #include <sstream>
29 #include <algorithm>
30 #include <string.h>
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
58 namespace boost {
59 namespace wave {
60 namespace iteration_context_policies {
62 struct vfs_file_to_string {
63 template <typename IterContext>
64 class inner {
65 public:
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;
72 // read in the file
73 tre::FileIStream file(iter_ctx.filename.c_str());
74 if(!file.is_open()) {
75 BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception,
76 bad_include_file, iter_ctx.filename.c_str(), act_pos);
77 return;
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),
87 language);
88 iter_ctx.last = iterator_type();
90 private:
91 std::string instring;
98 #endif /* BUILD_CG_PREPROCESSOR */
100 namespace tre {
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));
123 } else {
124 pos->second = 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());
146 EffectPtr res;
147 try {
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;
157 pos->second = res;
158 return res;
161 CgEffect::CgEffect(const std::string & filename)
163 #ifdef BUILD_CG_PREPROCESSOR
164 // read the while effect file into memory
165 FileIStream file(filename);
166 if(!file.is_open())
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
176 input_policy_type;
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 */
200 if(!effect_) {
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_);
213 if(technique_) {
214 vLog << info("Cg") << "Using technique " << cgGetTechniqueName(technique_)
215 << "." << std::endl;
216 } else {
217 throw(Exception("No valid technique."));
220 // enumerate effect parameters
221 CGparameter par = cgGetFirstEffectParameter(effect_);
222 while(par) {
223 const char * sem = cgGetParameterSemantic(par);
225 // internals
226 if(sem && *sem) {
227 if(strcasecmp(sem, "Time") == 0) {
228 const char * str;
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));
235 } else {
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);
247 // user uniforms
248 } else {
249 const char * name = cgGetParameterName(par);
251 switch(cgGetParameterType(par)) {
252 case CG_FLOAT:
253 case CG_HALF:
254 case CG_FIXED:
255 case CG_FLOAT1:
256 case CG_HALF1:
257 case CG_FIXED1:
258 params_.push_back(EffectParameter(name, par, vtFloat1));
259 break;
260 case CG_FLOAT2:
261 case CG_HALF2:
262 case CG_FIXED2:
263 params_.push_back(EffectParameter(name, par, vtFloat2));
264 break;
265 case CG_FLOAT3:
266 case CG_HALF3:
267 case CG_FIXED3:
268 params_.push_back(EffectParameter(name, par, vtFloat3));
269 break;
270 case CG_FLOAT4:
271 case CG_HALF4:
272 case CG_FIXED4:
273 params_.push_back(EffectParameter(name, par, vtFloat4));
274 break;
275 case CG_INT:
276 case CG_BOOL:
277 case CG_INT1:
278 case CG_BOOL1:
279 params_.push_back(EffectParameter(name, par, vtInt1));
280 break;
281 case CG_INT2:
282 case CG_BOOL2:
283 params_.push_back(EffectParameter(name, par, vtInt2));
284 break;
285 case CG_INT3:
286 case CG_BOOL3:
287 params_.push_back(EffectParameter(name, par, vtInt3));
288 break;
289 case CG_INT4:
290 case CG_BOOL4:
291 params_.push_back(EffectParameter(name, par, vtInt4));
292 break;
293 case CG_SAMPLER1D:
294 case CG_SAMPLER2D:
295 case CG_SAMPLER3D:
296 case CG_SAMPLERRECT:
297 case CG_SAMPLERCUBE:
298 params_.push_back(EffectParameter(name, par, vtTexture));
299 break;
300 // ignore the rest
301 default:
302 break;
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
318 // floats
319 for(FVarVector::const_iterator itr = vars.fvars.begin();
320 itr != vars.fvars.end(); ++itr) {
321 ChangeFloatVariable(itr->first, itr->second);
324 // ints
325 for(IVarVector::const_iterator itr = vars.ivars.begin();
326 itr != vars.ivars.end(); ++itr) {
327 ChangeIntVariable(itr->first, itr->second);
330 // textures
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)
344 return;
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)
357 return;
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)
370 return;
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;
380 const CGbool * vals;
381 CGannotation ann;
382 int n;
384 ann = cgGetNamedParameterAnnotation(par, "inverse");
385 if(ann && (vals = cgGetBoolAnnotationValues(ann, &n)) && n > 0)
386 inv = vals[0];
388 ann = cgGetNamedParameterAnnotation(par, "transpose");
389 if(ann && (vals = cgGetBoolAnnotationValues(ann, &n)) && n > 0)
390 trans = vals[0];
392 if(inv && trans) {
393 internals_.push_back(std::make_pair(
394 static_cast<InternalsType>(base + 3), par));
395 } else if(inv) {
396 internals_.push_back(std::make_pair(
397 static_cast<InternalsType>(base + 1), par));
398 } else if(trans) {
399 internals_.push_back(std::make_pair(
400 static_cast<InternalsType>(base + 2), par));
401 } else {
402 internals_.push_back(std::make_pair(base, par));