/** * projectM -- Milkdrop-esque visualisation SDK * Copyright (C)2003-2004 projectM Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * See 'LICENSE.txt' included within this release * */ #include #include #include #ifdef WIN32 #include "win32-dirent.h" #else #include #endif /** WIN32 */ #include #include "projectM.h" #include "wipemalloc.h" #include "common.h" #include "compare.h" #include "fatal.h" #include "CustomWave.h" #include "CustomShape.h" #include "Expr.h" #include "Eval.h" #include "Func.h" #include "InitCond.h" #include "Param.h" #include "Parser.h" #include "PerFrameEqn.h" #include "PerPixelEqn.h" #include "Preset.h" #include "SplayTree.h" Preset *preset_hack; Preset *Preset::active_preset = NULL; Preset *Preset::idle_preset = NULL; Preset *Preset::old_preset = NULL; FILE * write_stream = NULL; /** Initialise the idle preset */ Preset *Preset::init_idle_preset() { Preset *preset = NULL; /* Initialize idle preset struct */ if ((preset = (Preset*)wipemalloc(sizeof(Preset))) == NULL) return NULL; strncpy(preset->name, "idlepreset", strlen("idlepreset")); /* Initialize equation trees */ preset->init_cond_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string, (void*(*)(void*))copy_string, (void(*)(void*))free_string); preset->user_param_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string,(void*(*)(void*)) copy_string, (void(*)(void*))free_string); preset->per_frame_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int,(void*(*)(void*)) copy_int, (void(*)(void*))free_int); preset->per_pixel_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int, (void*(*)(void*))copy_int, (void(*)(void*))free_int); preset->per_frame_init_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string,(void*(*)(void*)) copy_string, (void(*)(void*))free_string); preset->custom_wave_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int, (void*(*)(void*))copy_int, (void(*)(void*))free_int); preset->custom_shape_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int,(void*(*)(void*)) copy_int, (void(*)(void*))free_int); /* Set file path to dummy name */ strncpy(preset->file_path, "IDLE PRESET", MAX_PATH_SIZE-1); /* Set initial index values */ preset->per_pixel_eqn_string_index = 0; preset->per_frame_eqn_string_index = 0; preset->per_frame_init_eqn_string_index = 0; memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS); /* Clear string buffers */ memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE); memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE); memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE); idle_preset = preset; return preset; } int Preset::destroy_idle_preset() { idle_preset->destroy(); idle_preset = NULL; return PROJECTM_SUCCESS; } int Preset::destroy() { return close_preset(); } void Preset::evalCustomShapeInitConditions() { custom_shape_tree->splay_traverse( eval_custom_shape_init_conds_helper ); } void Preset::evalCustomWaveInitConditions() { custom_wave_tree->splay_traverse( eval_custom_wave_init_conds_helper ); } void Preset::evalInitConditions() { per_frame_init_eqn_tree->splay_traverse((void (*)(void*))eval_init_cond_helper); } void Preset::evalPerFrameEquations() { init_cond_tree->splay_traverse((void (*)(void*))eval_init_cond_helper); per_frame_eqn_tree->splay_traverse((void (*)(void*))eval_per_frame_eqn_helper); } /* Private function to close a preset file */ int Preset::close_preset() { #if defined(PRESET_DEBUG) && defined(DEBUG) DWRITE( "close_preset(): in\n" ); #endif init_cond_tree->splay_traverse((void (*)(void*))free_init_cond_helper); delete init_cond_tree; per_frame_init_eqn_tree->splay_traverse((void (*)(void*))free_init_cond_helper); delete per_frame_init_eqn_tree; per_pixel_eqn_tree->splay_traverse((void (*)(void*))free_per_pixel_eqn_helper); delete per_pixel_eqn_tree; per_frame_eqn_tree->splay_traverse((void (*)(void*))free_per_frame_eqn_helper); delete per_frame_eqn_tree; user_param_tree->splay_traverse((void (*)(void*))free_param_helper); delete user_param_tree; custom_wave_tree->splay_traverse((void (*)(void*))free_custom_wave_helper); delete custom_wave_tree; custom_shape_tree->splay_traverse((void (*)(void*))free_custom_shape_helper); delete custom_shape_tree; #if defined(PRESET_DEBUG) && defined(DEBUG) DWRITE( "close_preset(): out\n" ); #endif return PROJECTM_SUCCESS; } void Preset::reloadPerPixel(char *s) { int slen; if (s == NULL) return; /* Clear previous per pixel equations */ per_pixel_eqn_tree->splay_traverse((void (*)(void*))free_per_pixel_eqn_helper); delete per_pixel_eqn_tree; per_pixel_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int, (void* (*)(void*))copy_int, (void (*)(void*))free_int); /* Convert string to a stream */ #if !defined(MACOS) && !defined(WIN32) { FILE* fs = fmemopen (s, strlen(s), "r"); char c; while ((c = fgetc(fs)) != EOF) { ungetc(c, fs); //FIXME Parser::parse_per_pixel_eqn(fs, preset, 0); } fclose(fs); } #else printf( "reloadPerPixel()\n" ); #endif /* Clear string space */ memset(per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE); /* Compute length of string */ slen = strlen(s); /* Copy new string into buffer */ strncpy(per_pixel_eqn_string_buffer, s, slen); /* Yet again no bounds checking */ per_pixel_eqn_string_index = slen; /* Finished */ return; } /* Obviously unwritten */ void Preset::reloadPerFrameInit(char *s) { } void Preset::reloadPerFrame(char * s) { int slen; int eqn_count = 1; if (s == NULL) return; /* Clear previous per frame equations */ per_frame_eqn_tree->splay_traverse((void (*)(void*))free_per_frame_eqn_helper ); delete per_frame_eqn_tree; per_frame_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int,(void* (*)(void*)) copy_int, (void (*)(void*))free_int); /* Convert string to a stream */ //FIXME #if !defined(MACOS) && !defined(WIN32) && !defined(LINUX) { FILE* fs = fmemopen (s, strlen(s), "r"); char c; while ((c = fgetc(fs)) != EOF) { per_frame_eqn_t * per_frame; ungetc(c, fs); if ((per_frame = Parser::parse_per_frame_eqn(fs, eqn_count, preset)) != NULL) { splay_insert(per_frame, &eqn_count, preset->per_frame_eqn_tree); eqn_count++; } } fclose(fs); } #else printf( "reloadPerFrame()\n" ); #endif /* Clear string space */ memset(per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE); /* Compute length of string */ slen = strlen(s); /* Copy new string into buffer */ strncpy(per_frame_eqn_string_buffer, s, slen); /* Yet again no bounds checking */ per_frame_eqn_string_index = slen; /* Finished */ printf("reloadPerFrame: %d eqns parsed succesfully\n", eqn_count-1); return; } Preset * Preset::load_preset(const char * pathname) { Preset * preset; printf( "loading preset from '%s'\n", pathname ); /* Initialize preset struct */ if ((preset = (Preset*)wipemalloc(sizeof(Preset))) == NULL) return NULL; /* Initialize equation trees */ preset->init_cond_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string, (void* (*)(void*))copy_string, (void (*)(void*))free_string); preset->user_param_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string,(void* (*)(void*)) copy_string, (void (*)(void*))free_string); preset->per_frame_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int,(void* (*)(void*)) copy_int, (void (*)(void*)) free_int); preset->per_pixel_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int,(void* (*)(void*)) copy_int, (void (*)(void*)) free_int); preset->per_frame_init_eqn_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_string,(void* (*)(void*)) copy_string, (void (*)(void*)) free_string); preset->custom_wave_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int, (void* (*)(void*))copy_int, (void (*)(void*)) free_int); preset->custom_shape_tree = SplayTree::create_splaytree((int (*)(void*,void*))compare_int, (void* (*)(void*))copy_int, (void (*)(void*)) free_int); memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS); /* Copy file path */ if ( pathname == NULL ) { preset->close_preset(); return NULL; } strncpy(preset->file_path, pathname, MAX_PATH_SIZE-1); /* Set initial index values */ preset->per_pixel_eqn_string_index = 0; preset->per_frame_eqn_string_index = 0; preset->per_frame_init_eqn_string_index = 0; /* Clear string buffers */ memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE); memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE); memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE); if (projectM::currentEngine->load_preset_file(pathname, preset) < 0) { #ifdef PRESET_DEBUG if (PRESET_DEBUG) printf("load_preset: failed to load file \"%s\"\n", pathname); #endif preset->close_preset(); return NULL; } /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */ preset->per_frame_eqn_count = 0; preset->per_frame_init_eqn_count = 0; /* Finished, return new preset */ return preset; } void Preset::savePreset(char * filename) { #ifdef PANTS FILE * fs; if (filename == NULL) return; /* Open the file corresponding to pathname */ if ((fs = fopen(filename, "w+")) == 0) { #ifdef PRESET_DEBUG if (PRESET_DEBUG) printf("savePreset: failed to create filename \"%s\"!\n", filename); #endif return; } write_stream = fs; if (write_preset_name(fs) < 0) { write_stream = NULL; fclose(fs); return; } if (write_init_conditions(fs) < 0) { write_stream = NULL; fclose(fs); return; } if (write_per_frame_init_equations(fs) < 0) { write_stream = NULL; fclose(fs); return; } if (write_per_frame_equations(fs) < 0) { write_stream = NULL; fclose(fs); return; } if (write_per_pixel_equations(fs) < 0) { write_stream = NULL; fclose(fs); return; } write_stream = NULL; fclose(fs); #endif } int Preset::write_preset_name(FILE * fs) { char s[256]; int len; memset(s, 0, 256); if (fs == NULL) return PROJECTM_FAILURE; /* Format the preset name in a string */ sprintf(s, "[%s]\n", name); len = strlen(s); /* Write preset name to file stream */ if (fwrite(s, 1, len, fs) != len) return PROJECTM_FAILURE; return PROJECTM_SUCCESS; } #ifdef NEEDS_MOVED int Preset::write_init_conditions(FILE * fs) { if (fs == NULL) return PROJECTM_FAILURE; init_cond_tree->splay_traverse( (void (*)(void*))write_init); return PROJECTM_SUCCESS; } void Preset::write_init( InitCond * init_cond ) { char s[512]; int len; if (write_stream == NULL) return; memset(s, 0, 512); if (init_cond->param->type == P_TYPE_BOOL) sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val); else if (init_cond->param->type == P_TYPE_INT) sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val); else if (init_cond->param->type == P_TYPE_DOUBLE) sprintf(s, "%s=%f\n", init_cond->param->name, init_cond->init_val.float_val); else { printf("write_init: unknown parameter type!\n"); return; } len = strlen(s); if ((fwrite(s, 1, len, write_stream)) != len) printf("write_init: failed writing to file stream! Out of disk space?\n"); } int Preset::write_per_frame_init_equations(FILE * fs) { int len; if (fs == NULL) return PROJECTM_FAILURE; len = strlen(per_frame_init_eqn_string_buffer); if (fwrite(per_frame_init_eqn_string_buffer, 1, len, fs) != len) return PROJECTM_FAILURE; return PROJECTM_SUCCESS; } int Preset::write_per_frame_equations(FILE * fs) { int len; if (fs == NULL) return PROJECTM_FAILURE; len = strlen(per_frame_eqn_string_buffer); if (fwrite(per_frame_eqn_string_buffer, 1, len, fs) != len) return PROJECTM_FAILURE; return PROJECTM_SUCCESS; } int Preset::write_per_pixel_equations(FILE * fs) { int len; if (fs == NULL) return PROJECTM_FAILURE; len = strlen(per_pixel_eqn_string_buffer); if (fwrite(per_pixel_eqn_string_buffer, 1, len, fs) != len) return PROJECTM_FAILURE; return PROJECTM_SUCCESS; } #endif /** NEEDS_MOVED */ void Preset::load_custom_wave_init_conditions() { custom_wave_tree->splay_traverse((void (*)(void*))load_custom_wave_init_helper); } void Preset::load_custom_shape_init_conditions() { custom_shape_tree->splay_traverse((void (*)(void*))load_custom_shape_init_helper); } /** Returns the next custom waveform in the wave database */ CustomWave *Preset::nextCustomWave() { CustomWave *interface_wave = NULL; if ( (interface_wave = (CustomWave *)custom_wave_tree->splay_find(&interface_id) ) == NULL ) { interface_id = 0; return interface_wave; } interface_id++; /** Evaluate all per frame equations associated with this wave */ interface_wave->init_cond_tree->splay_traverse((void (*)(void*))eval_init_cond_helper); interface_wave->per_frame_eqn_tree->splay_traverse((void (*)(void*))eval_per_frame_eqn_helper); return interface_wave; } /** Returns the next custom shape in the shape database */ CustomShape *Preset::nextCustomShape() { CustomShape *interface_shape = NULL; if ( (interface_shape = (CustomShape *)custom_shape_tree->splay_find(&cwave_interface_id) ) == NULL ) { cwave_interface_id = 0; return interface_shape; } cwave_interface_id++; /** Evaluate all per frame equations associated with this wave */ interface_shape->init_cond_tree->splay_traverse((void (*)(void*))eval_init_cond_helper); interface_shape->per_frame_eqn_tree->splay_traverse((void (*)(void*))eval_per_frame_eqn_helper); return interface_shape; } /** Evaluates all per-pixel equations */ void Preset::evalPerPixelEqns() { /* Evaluate all per pixel equations using splay traversal */ per_pixel_eqn_tree->splay_traverse((void (*)(void*))eval_per_pixel_eqn_helper); /* Set mesh i / j values to -1 so engine vars are used by default again */ projectM::currentEngine->mesh_i = -1; projectM::currentEngine->mesh_j = -1; } /** Is the opcode a per-pixel equation? */ int Preset::isPerPixelEqn( int op ) { return per_pixel_flag[op]; } /** Reset all per-pixel equation flags */ int Preset::resetPerPixelEqnFlags() { int i; for (i = 0; i < NUM_OPS;i++) { per_pixel_flag[i] = FALSE; } return PROJECTM_SUCCESS; } /* Adds a per pixel equation according to its string name. This will be used only by the parser */ int Preset::add_per_pixel_eqn(char * name, GenExpr * gen_expr) { PerPixelEqn * per_pixel_eqn = NULL; int index; Param * param = NULL; /* Argument checks */ if (gen_expr == NULL) return PROJECTM_FAILURE; if (name == NULL) return PROJECTM_FAILURE; if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: per pixel equation (name = \"%s\")\n", name); if (!strncmp(name, "dx", strlen("dx"))) per_pixel_flag[DX_OP] = TRUE; else if (!strncmp(name, "dy", strlen("dy"))) per_pixel_flag[DY_OP] = TRUE; else if (!strncmp(name, "cx", strlen("cx"))) per_pixel_flag[CX_OP] = TRUE; else if (!strncmp(name, "cy", strlen("cy"))) per_pixel_flag[CX_OP] = TRUE; else if (!strncmp(name, "zoom", strlen("zoom"))) per_pixel_flag[ZOOM_OP] = TRUE; else if (!strncmp(name, "zoomexp", strlen("zoomexp"))) per_pixel_flag[ZOOMEXP_OP] = TRUE; else if (!strncmp(name, "rot", strlen("rot"))) per_pixel_flag[ROT_OP] = TRUE; else if (!strncmp(name, "sx", strlen("sx"))) per_pixel_flag[SX_OP] = TRUE; else if (!strncmp(name, "sy", strlen("sy"))) per_pixel_flag[SY_OP] = TRUE; /* Search for the parameter so we know what matrix the per pixel equation is referencing */ param = Param::find_param(name, this, TRUE); if ( !param ) { if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to allocate a new parameter!\n"); return PROJECTM_FAILURE; } /** if ( !param->matrix ) { if (PER_PIXEL_EQN_DEBUG) printf( "add_per_pixel_eqn: failed to locate param matrix\n" ); return PROJECTM_FAILURE; } */ /* Find most largest index in the splaytree */ if ((per_pixel_eqn = (PerPixelEqn *)per_pixel_eqn_tree->splay_find_max()) == NULL) index = 0; else index = per_pixel_eqn_tree->splay_size(); /* Create the per pixel equation given the index, parameter, and general expression */ if ((per_pixel_eqn = PerPixelEqn::new_per_pixel_eqn(index, param, gen_expr)) == NULL) { if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to create new per pixel equation!\n"); return PROJECTM_FAILURE; } if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: new equation (index = %d,matrix=%X) (param = \"%s\")\n", per_pixel_eqn->index, per_pixel_eqn->param->matrix, per_pixel_eqn->param->name); /* Insert the per pixel equation into the preset per pixel database */ if (per_pixel_eqn_tree->splay_insert(per_pixel_eqn, &per_pixel_eqn->index) < 0) { per_pixel_eqn->free_per_pixel_eqn(); printf("failed to add per pixel eqn!\n"); return PROJECTM_FAILURE; } /* Done */ return PROJECTM_SUCCESS; } /* Finds / Creates (if necessary) initial condition associated with passed parameter */ InitCond *Preset::get_init_cond( Param *param ) { InitCond * init_cond; CValue init_val; if ( param == NULL ) { return NULL; } if ((init_cond = (InitCond*)(init_cond_tree->splay_find(param->name))) == NULL) { if (param->type == P_TYPE_BOOL) init_val.bool_val = 0; else if (param->type == P_TYPE_INT) init_val.int_val = *(int*)param->engine_val; else if (param->type == P_TYPE_DOUBLE) init_val.float_val = *(float*)param->engine_val; /* Create new initial condition */ if ((init_cond = new InitCond(param, init_val)) == NULL) return NULL; /* Insert the initial condition into this presets tree */ if (init_cond_tree->splay_insert(init_cond, init_cond->param->name) < 0) { delete init_cond; return NULL; } } return init_cond; }