PageRenderTime 62ms CodeModel.GetById 26ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/visualizations/XBMCProjectM/libprojectM/Preset.cpp

http://github.com/xbmc/xbmc
C++ | 544 lines | 324 code | 155 blank | 65 comment | 76 complexity | 5c6540c7edc02337597093254552177a MD5 | raw file
  1/**
  2 * projectM -- Milkdrop-esque visualisation SDK
  3 * Copyright (C)2003-2004 projectM Team
  4 *
  5 * This library is free software; you can redistribute it and/or
  6 * modify it under the terms of the GNU Lesser General Public
  7 * License as published by the Free Software Foundation; either
  8 * version 2.1 of the License, or (at your option) any later version.
  9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18 * See 'LICENSE.txt' included within this release
 19 *
 20 */
 21
 22#include <stdio.h>
 23#include <string.h>
 24#include <stdlib.h>
 25#include <fcntl.h>
 26#ifdef WIN32
 27#include "win32-dirent.h"
 28#else
 29#include <dirent.h>
 30#endif /** WIN32 */
 31#include <time.h>
 32
 33#include "Preset.hpp"
 34#include "Parser.hpp"
 35#include "ParamUtils.hpp"
 36#include "InitCondUtils.hpp"
 37#include "fatal.h"
 38#include <iostream>
 39#include <sstream>
 40
 41Preset::Preset(std::istream & in, const std::string & presetName, PresetInputs & presetInputs, PresetOutputs & presetOutputs):
 42    builtinParams(presetInputs, presetOutputs),
 43    m_presetName(presetName),
 44    m_presetOutputs(presetOutputs),
 45    m_presetInputs(presetInputs)
 46{
 47
 48  m_presetOutputs.customWaves.clear();
 49  m_presetOutputs.customShapes.clear();
 50
 51  initialize(in);
 52
 53}
 54
 55
 56Preset::Preset(const std::string & absoluteFilePath, const std::string & presetName,  PresetInputs & presetInputs, PresetOutputs & presetOutputs):
 57    builtinParams(presetInputs, presetOutputs),
 58    m_absoluteFilePath(absoluteFilePath),
 59    m_presetName(presetName),
 60    m_presetOutputs(presetOutputs),
 61    m_presetInputs(presetInputs)
 62{
 63
 64  m_presetOutputs.customWaves.clear();
 65  m_presetOutputs.customShapes.clear();
 66  
 67  initialize(absoluteFilePath);
 68
 69}
 70
 71Preset::~Preset()
 72{
 73
 74  Algorithms::traverse<Algorithms::TraverseFunctors::DeleteFunctor<InitCond> >(init_cond_tree);
 75
 76  Algorithms::traverse<Algorithms::TraverseFunctors::DeleteFunctor<InitCond> >(per_frame_init_eqn_tree);
 77
 78  Algorithms::traverse<Algorithms::TraverseFunctors::DeleteFunctor<PerPixelEqn> >(per_pixel_eqn_tree);
 79
 80  Algorithms::traverseVector<Algorithms::TraverseFunctors::DeleteFunctor<PerFrameEqn> >(per_frame_eqn_tree);
 81
 82  Algorithms::traverse<Algorithms::TraverseFunctors::DeleteFunctor<Param> >(user_param_tree);
 83
 84  for (PresetOutputs::cwave_container::iterator pos = customWaves.begin(); pos != customWaves.end(); ++pos)
 85  {
 86    	delete(*pos);
 87  }
 88
 89  for (PresetOutputs::cshape_container::iterator pos = customShapes.begin(); pos != customShapes.end(); ++pos)
 90  {
 91    	delete(*pos);
 92  }
 93
 94}
 95
 96/* Adds a per pixel equation according to its string name. This
 97   will be used only by the parser */
 98
 99int Preset::add_per_pixel_eqn(char * name, GenExpr * gen_expr)
100{
101
102  PerPixelEqn * per_pixel_eqn = NULL;
103  int index;
104  Param * param = NULL;
105
106  assert(gen_expr);
107  assert(name);
108
109  if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: per pixel equation (name = \"%s\")\n", name);
110 
111
112  /* Search for the parameter so we know what matrix the per pixel equation is referencing */
113
114  param = ParamUtils::find(name, &this->builtinParams, &this->user_param_tree);
115  if ( !param )
116  {
117    if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to allocate a new parameter!\n");
118    return PROJECTM_FAILURE;
119  }
120
121  index = per_pixel_eqn_tree.size();
122
123  /* Create the per pixel equation given the index, parameter, and general expression */
124  if ((per_pixel_eqn = new PerPixelEqn(index, param, gen_expr)) == NULL)
125  {
126    if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to create new per pixel equation!\n");
127    return PROJECTM_FAILURE;
128  }
129
130
131
132
133  /* Insert the per pixel equation into the preset per pixel database */
134  std::pair<std::map<int, PerPixelEqn*>::iterator, bool> inserteeOption = per_pixel_eqn_tree.insert
135      (std::make_pair(per_pixel_eqn->index, per_pixel_eqn));
136
137  if (!inserteeOption.second)
138  {
139    printf("failed to add per pixel eqn!\n");
140    delete(per_pixel_eqn);
141    return PROJECTM_FAILURE;
142  }
143
144  /* Done */
145  return PROJECTM_SUCCESS;
146}
147
148void Preset::evalCustomShapeInitConditions()
149{
150
151  for (PresetOutputs::cshape_container::iterator pos = customShapes.begin(); pos != customShapes.end(); ++pos) {
152    assert(*pos);
153    (*pos)->evalInitConds();
154  }
155}
156
157
158void Preset::evalCustomWaveInitConditions()
159{
160
161  for (PresetOutputs::cwave_container::iterator pos = customWaves.begin(); pos != customWaves.end(); ++pos) {
162    assert(*pos);
163   (*pos)->evalInitConds();
164}
165}
166
167
168void Preset::evalCustomWavePerFrameEquations()
169{
170
171  for (PresetOutputs::cwave_container::iterator pos = customWaves.begin(); pos != customWaves.end(); ++pos)
172  {
173
174    std::map<std::string, InitCond*> & init_cond_tree = (*pos)->init_cond_tree;
175    for (std::map<std::string, InitCond*>::iterator _pos = init_cond_tree.begin(); _pos != init_cond_tree.end(); ++_pos)
176    {
177      assert(_pos->second);
178      _pos->second->evaluate();
179    }
180
181    std::vector<PerFrameEqn*> & per_frame_eqn_tree = (*pos)->per_frame_eqn_tree;
182    for (std::vector<PerFrameEqn*>::iterator _pos = per_frame_eqn_tree.begin(); _pos != per_frame_eqn_tree.end(); ++_pos)
183    {
184      (*_pos)->evaluate();
185    }
186  }
187
188}
189
190void Preset::evalCustomShapePerFrameEquations()
191{
192
193  for (PresetOutputs::cshape_container::iterator pos = customShapes.begin(); pos != customShapes.end(); ++pos)
194  {
195
196    std::map<std::string, InitCond*> & init_cond_tree = (*pos)->init_cond_tree;
197    for (std::map<std::string, InitCond*>::iterator _pos = init_cond_tree.begin(); _pos != init_cond_tree.end(); ++_pos)
198    {
199      assert(_pos->second);
200      _pos->second->evaluate();
201    }
202
203    std::vector<PerFrameEqn*> & per_frame_eqn_tree = (*pos)->per_frame_eqn_tree;
204    for (std::vector<PerFrameEqn*>::iterator _pos = per_frame_eqn_tree.begin(); _pos != per_frame_eqn_tree.end(); ++_pos)
205    {
206      (*_pos)->evaluate();
207    }
208  }
209
210}
211
212void Preset::evalPerFrameInitEquations()
213{
214
215  for (std::map<std::string, InitCond*>::iterator pos = per_frame_init_eqn_tree.begin(); pos != per_frame_init_eqn_tree.end(); ++pos)
216  {
217    assert(pos->second);
218    pos->second->evaluate();
219  }
220
221}
222
223void Preset::evalPerFrameEquations()
224{
225
226  for (std::map<std::string, InitCond*>::iterator pos = init_cond_tree.begin(); pos != init_cond_tree.end(); ++pos)
227  {
228    assert(pos->second);
229    pos->second->evaluate();
230  }
231
232  for (std::vector<PerFrameEqn*>::iterator pos = per_frame_eqn_tree.begin(); pos != per_frame_eqn_tree.end(); ++pos)
233  {
234    (*pos)->evaluate();
235  }
236
237}
238
239void Preset::preloadInitialize() {
240 
241  /// @note commented this out because it should be unnecessary
242  // Clear equation trees
243  //init_cond_tree.clear();
244  //user_param_tree.clear();
245  //per_frame_eqn_tree.clear();
246  //per_pixel_eqn_tree.clear();
247  //per_frame_init_eqn_tree.clear();
248
249
250}
251
252void Preset::postloadInitialize() {
253
254  /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */
255  this->per_frame_eqn_count = 0;
256  this->per_frame_init_eqn_count = 0;
257
258  this->loadBuiltinParamsUnspecInitConds();
259  this->loadCustomWaveUnspecInitConds();
260  this->loadCustomShapeUnspecInitConds();
261
262
263/// @bug are you handling all the q variables conditions? in particular, the un-init case?
264//m_presetOutputs.q1 = 0;
265//m_presetOutputs.q2 = 0;
266//m_presetOutputs.q3 = 0;
267//m_presetOutputs.q4 = 0;
268//m_presetOutputs.q5 = 0;
269//m_presetOutputs.q6 = 0;
270//m_presetOutputs.q7 = 0;
271//m_presetOutputs.q8 = 0;
272
273}
274
275void Preset::initialize(const std::string & pathname)
276{
277  int retval;
278
279  preloadInitialize();
280
281if (PRESET_DEBUG)
282  std::cerr << "[Preset] loading file \"" << pathname << "\"..." << std::endl;
283
284  if ((retval = loadPresetFile(pathname)) < 0)
285  {
286if (PRESET_DEBUG)
287     std::cerr << "[Preset] failed to load file \"" <<
288      pathname << "\"!" << std::endl;
289
290    /// @bug how should we handle this problem? a well define exception?
291    throw retval;
292  }
293
294  postloadInitialize();
295}
296
297void Preset::initialize(std::istream & in)
298{
299  int retval;
300
301  preloadInitialize();
302
303  if ((retval = readIn(in)) < 0)
304  {
305
306	if (PRESET_DEBUG)
307     std::cerr << "[Preset] failed to load from stream " << std::endl; 
308
309    /// @bug how should we handle this problem? a well define exception?
310    throw retval;
311  }
312
313  postloadInitialize();
314}
315
316void Preset::loadBuiltinParamsUnspecInitConds() {
317
318  InitCondUtils::LoadUnspecInitCond loadUnspecInitCond(this->init_cond_tree, this->per_frame_init_eqn_tree);
319
320  this->builtinParams.traverse(loadUnspecInitCond);
321  Algorithms::traverse(user_param_tree, loadUnspecInitCond);
322
323}
324
325void Preset::loadCustomWaveUnspecInitConds()
326{
327
328
329  for (PresetOutputs::cwave_container::iterator pos = customWaves.begin(); pos != customWaves.end(); ++pos)
330  {
331    assert(*pos);
332    (*pos)->loadUnspecInitConds();
333  }
334
335}
336
337void Preset::loadCustomShapeUnspecInitConds()
338{
339
340  for (PresetOutputs::cshape_container::iterator pos = customShapes.begin(); pos != customShapes.end(); ++pos)
341  {
342    assert(*pos);
343    (*pos)->loadUnspecInitConds();
344  }
345}
346
347
348void Preset::evaluateFrame()
349{
350
351  // Evaluate all equation objects according to milkdrop flow diagram 
352
353  evalPerFrameInitEquations();
354  
355  evalPerFrameEquations();
356
357
358  // Important step to ensure custom shapes and waves don't stamp on the q variable values 
359  // calculated by the per frame (init) and per pixel equations.
360  transfer_q_variables(customWaves);
361  transfer_q_variables(customShapes);
362
363  initialize_PerPixelMeshes();
364
365  evalPerPixelEqns();
366
367  evalCustomWaveInitConditions();
368  evalCustomWavePerFrameEquations();
369
370  evalCustomShapeInitConditions();
371  evalCustomShapePerFrameEquations();
372
373  // Setup pointers of the custom waves and shapes to the preset outputs instance
374  /// @slow an extra O(N) per frame, could do this during eval
375  m_presetOutputs.customWaves = PresetOutputs::cwave_container(customWaves); 
376  m_presetOutputs.customShapes = PresetOutputs::cshape_container(customShapes);
377
378}
379
380void Preset::initialize_PerPixelMeshes()
381{
382
383  int x,y;
384      for (x=0;x<m_presetInputs.gx;x++){       
385	for(y=0;y<m_presetInputs.gy;y++){
386	  m_presetOutputs.cx_mesh[x][y]=m_presetOutputs.cx;
387	}}
388	
389     
390   
391
392      for (x=0;x<m_presetInputs.gx;x++){
393	for(y=0;y<m_presetInputs.gy;y++){
394	  m_presetOutputs.cy_mesh[x][y]=m_presetOutputs.cy;
395	}}
396    
397  
398 
399      for (x=0;x<m_presetInputs.gx;x++){
400	for(y=0;y<m_presetInputs.gy;y++){
401	  m_presetOutputs.sx_mesh[x][y]=m_presetOutputs.sx;
402	}}
403    
404  
405
406    
407      for (x=0;x<m_presetInputs.gx;x++){
408	for(y=0;y<m_presetInputs.gy;y++){
409	  m_presetOutputs.sy_mesh[x][y]=m_presetOutputs.sy;
410	}}
411    
412
413     
414      for (x=0;x<m_presetInputs.gx;x++){
415	for(y=0;y<m_presetInputs.gy;y++){
416	  m_presetOutputs.dx_mesh[x][y]=m_presetOutputs.dx;
417	}}
418    
419  
420     
421      for (x=0;x<m_presetInputs.gx;x++){
422	for(y=0;y<m_presetInputs.gy;y++){
423	  m_presetOutputs.dy_mesh[x][y]=m_presetOutputs.dy;
424	}}
425    
426
427    
428      for (x=0;x<m_presetInputs.gx;x++){
429	for(y=0;y<m_presetInputs.gy;y++){
430	  m_presetOutputs.zoom_mesh[x][y]=m_presetOutputs.zoom;
431	}}
432    
433 
434
435    
436      for (x=0;x<m_presetInputs.gx;x++){
437	for(y=0;y<m_presetInputs.gy;y++){
438	  m_presetOutputs.zoomexp_mesh[x][y]=m_presetOutputs.zoomexp; 
439	}}
440    
441
442  
443      for (x=0;x<m_presetInputs.gx;x++){
444	for(y=0;y<m_presetInputs.gy;y++){
445	  m_presetOutputs.rot_mesh[x][y]=m_presetOutputs.rot;
446	}}
447    
448
449      for (x=0;x<m_presetInputs.gx;x++){
450	for(y=0;y<m_presetInputs.gy;y++){
451	  m_presetOutputs.warp_mesh[x][y]=m_presetOutputs.warp;
452	}}
453    
454
455
456}
457// Evaluates all per-pixel equations 
458void Preset::evalPerPixelEqns()
459{
460
461  /* Evaluate all per pixel equations in the tree datastructure */
462  for (int mesh_x = 0; mesh_x < m_presetInputs.gx; mesh_x++)
463	  for (int mesh_y = 0; mesh_y < m_presetInputs.gy; mesh_y++)
464  for (std::map<int, PerPixelEqn*>::iterator pos = per_pixel_eqn_tree.begin();
465       pos != per_pixel_eqn_tree.end(); ++pos)
466    pos->second->evaluate(mesh_x, mesh_y);
467
468}
469
470int Preset::readIn(std::istream & fs) {
471
472  line_mode_t line_mode;
473
474  /* Parse any comments */
475  if (Parser::parse_top_comment(fs) < 0)
476  {
477	if (PRESET_DEBUG)
478    		std::cerr << "[Preset::readIn] no left bracket found..." << std::endl;
479    return PROJECTM_FAILURE;
480  }
481
482  /* Parse the preset name and a left bracket */
483  char tmp_name[MAX_TOKEN_SIZE];
484
485  if (Parser::parse_preset_name(fs, tmp_name) < 0)
486  {
487    std::cerr <<  "[Preset::readIn] loading of preset name failed" << std::endl;
488    return PROJECTM_ERROR;
489  }
490
491  /// @note  We ignore the preset name because [preset00] is just not so useful
492
493  // Loop through each line in file, trying to succesfully parse the file. 
494  // If a line does not parse correctly, keep trucking along to next line.
495  int retval;
496  while ((retval = Parser::parse_line(fs, this)) != EOF)
497  {
498    if (retval == PROJECTM_PARSE_ERROR)
499    {
500      line_mode = UNSET_LINE_MODE;
501      // std::cerr << "[Preset::readIn()] parse error in file \"" << this->absoluteFilePath() << "\"" << std::endl;
502    }
503  }
504
505//  std::cerr << "loadPresetFile: finished line parsing successfully" << std::endl;
506
507  /* Now the preset has been loaded.
508     Evaluation calls can be made at appropiate
509     times in the frame loop */
510
511return PROJECTM_SUCCESS;
512}
513
514/* loadPresetFile: private function that loads a specific preset denoted
515   by the given pathname */
516int Preset::loadPresetFile(const std::string & pathname)
517{
518  /* Open the file corresponding to pathname */
519  FILE* f = fopen(pathname.c_str(), "r");
520  if (!f) {
521    if (PRESET_DEBUG)
522    	std::cerr << "loadPresetFile: loading of file \"" << pathname << "\" failed!\n";
523    return PROJECTM_ERROR;
524  }
525
526  fseek(f, 0, SEEK_END);
527  long fsize = ftell(f);
528  rewind(f);
529  std::vector<char> buffer(fsize);
530
531  int err = fread(&buffer[0], 1, fsize, f);
532  if (!err)
533  {
534    printf("read failed\n");
535    fclose(f);
536    return PROJECTM_ERROR;
537  }
538
539  fclose(f);
540  std::stringstream stream;
541  stream.rdbuf()->pubsetbuf(&buffer[0],buffer.size());
542  return readIn(stream);
543}
544