/* scivi - visualization plugin for XMMS * Copyright (C) 2003 Vitaly V. Bursov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #define DUMP_BYTECODE 0 #include #include #include #include #include #include #include #include #include #include "glstuff.h" #ifdef HAVE_LIMITS_H # include #else # define INT_MAX 2147483647 #endif #include "common.h" #include "dynam.h" #include "mathlex.lex.h" #include "mathcompile.h" #define RNG_SVID int mathparse(void *p); static void load_dynamics_defaults(DynamicsData *d) { d->i_zoom = 1.0f; d->i_rot = 0.0f; d->i_cx = 0.0f; d->i_cy = 0.0f; d->i_dx = 0.0f; d->i_dy = 0.0f; d->i_sx = 1.0f; d->i_sy = 1.0f; d->i_ox = 0.0f; d->i_oy = 0.0f; d->i_decay = 1.0f; d->i_envR = 0.0f; d->i_envG = 0.0f; d->i_envB = 0.0f; d->i_envA = 1.0f; d->i_oscR = 1.0f; d->i_oscG = 1.0f; d->i_oscB = 1.0f; d->i_oscA = 1.0f; d->i_obR = 1.0f; d->i_obG = 1.0f; d->i_obB = 1.0f; d->i_obA = 0.0f; d->i_ob_width = 0.0f; d->i_ibR = 1.0f; d->i_ibG = 1.0f; d->i_ibB = 1.0f; d->i_ibA = 0.0f; d->i_ib_width = 0.0f; d->osc_look = 1; d->osc_look_param1 = 1.0f; d->osc_look_param2 = 0.2f; d->osc_additive = 1; d->osc_resolution = 0; d->osc_type = 0; d->osc_angle = 0.0f; d->osc_size = 1.0f; d->osc_amplitude = 1.0f; d->tex_wrap = 0; d->tex_invert = 0; d->tex_solarize = 0; d->opt_wireframe = 0; memset(&d->freqs, 0, sizeof(d->freqs)); /* avoiding zeros: set to volume of sample */ d->freqs.maxf[0] = 1.0f/32768.0f; d->freqs.maxf[1] = 1.0f/32768.0f; d->freqs.maxf[2] = 1.0f/32768.0f; d->const_pi = M_PI; d->const_e = M_E; d->const_sqrt2 = M_SQRT2; d->const_begin_points = GL_POINTS; d->const_begin_lines = GL_LINES; d->const_begin_line_strip = GL_LINE_STRIP; d->const_begin_line_loop = GL_LINE_LOOP; d->const_begin_triangles = GL_TRIANGLES; d->const_begin_triangle_strip = GL_TRIANGLE_STRIP; d->const_begin_triangle_fan = GL_TRIANGLE_FAN; d->const_begin_quads = GL_QUADS; d->const_begin_quad_strip = GL_QUAD_STRIP; d->const_begin_polygon = GL_POLYGON; } #define FLAGS_NONE (0) #define FLAG_INLOOP (1<<0) #define FLAG_BREAK (1<<1) #define FLAG_CONTINUE (1<<2) #define FLAGS_LOOPCTL (FLAG_BREAK | FLAG_CONTINUE) #define FLAG_SET(_f_) ((ded->flags) |= (_f_)) #define FLAG_IS_SET(_f_) ((ded->flags) & (_f_)) #define FLAG_CLEAR(_f_) ((ded->flags) &= ~(_f_)) struct Dyn_EvalOp_Data { DynamicsData *d; int codelen; float res; unsigned int flags; }; static void interpreter_ice(int p1, int p2, int p3, int p4) { static int warned = 0; if (warned) return; warned = 1; Xprintf("Internal interpreter error.\n%d.%d.%d.%d", p1, p2, p3, p4); } static int Dyn_EvalOp(struct Dyn_EvalOp_Data *ded, Code *bytecode, int codeoffs) { int opcode; int beval = 0; #define RES (ded->res) #define CO (codeoffs+beval) #define COO(_a_) (codeoffs+(_a_)) /*dprintf("starting: %p:%d\n", bytecode, CO);*/ /*dprintf("called from: %p\n", __builtin_return_address(0));*/ opcode = bytecode[CO].i; beval++; /*dprintf("opcode: %d\n", opcode);*/ switch (opcode) { case NOP: RES = 0.0f; break; case FLOAT: RES = bytecode[CO].f; beval++; break; case NEGATE: beval += Dyn_EvalOp(ded, bytecode, CO); RES = -RES; break; #define BINARY(__op__) { \ float r1, r2; \ beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES;\ beval += Dyn_EvalOp(ded, bytecode, CO); r2 = RES;\ RES = r1 __op__ r2; \ /*dprintf("BIN OP: " #__op__ "%f %f %f %d\n",r1,r2,RES,beval);*/\ break; \ } case PLUS: BINARY(+) case MINUS: BINARY(-) case DIVIDE: BINARY(/) case MULTIPLY: BINARY(*) #undef BINARY #define BINARY_CMP(__op__) { \ float r1, r2; \ beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES;\ beval += Dyn_EvalOp(ded, bytecode, CO); r2 = RES;\ RES = (r1 __op__ r2) ? 1.0f : 0.0f; \ break; \ } case GREAT: BINARY_CMP(>) case LESS: BINARY_CMP(<) case GREAT_EQ: BINARY_CMP(>=) case LESS_EQ: BINARY_CMP(<=) case EQUAL: BINARY_CMP(==) case NEQUAL: BINARY_CMP(!=) #undef BINARY_CMP #define BINARY_LOG(__op__) { \ float r1, r2; \ beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES;\ beval += Dyn_EvalOp(ded, bytecode, CO); r2 = RES;\ RES = (float)(((int)r1) __op__ ((int)r2)); \ break; \ } case MOD: BINARY_LOG(%) case OR: BINARY_LOG(|) case AND: BINARY_LOG(&) case XOR: BINARY_LOG(^) case NOT:{ beval += Dyn_EvalOp(ded, bytecode, CO); RES = (float)(~((int)RES)); break; } case LNOT:{ beval += Dyn_EvalOp(ded, bytecode, CO); RES = ((int)RES) ? 0.0f : 1.0f; break; } #undef BINARY_LOG case OROR:{ float r; int sec_offs = bytecode[CO].i; beval++; beval += Dyn_EvalOp(ded, bytecode, CO); if ((int)RES){ beval += sec_offs; RES = 1.0f; } else { beval += Dyn_EvalOp(ded, bytecode, CO); RES = ((int)RES) ? 1.0f : 0.0f; } break; } case ANDAND:{ float r; int sec_offs = bytecode[CO].i; beval++; beval += Dyn_EvalOp(ded, bytecode, CO); if (!((int)RES)){ beval += sec_offs; RES = 0.0f; } else { beval += Dyn_EvalOp(ded, bytecode, CO); RES = ((int)RES) ? 1.0f : 0.0f; } break; } /* * * Built-in functions * */ case FRESET_TO_DEFAULTS: load_dynamics_defaults(ded->d); break; case FDEBUG_PRINT: beval += Dyn_EvalOp(ded, bytecode, CO); printf("DPRINT: %f\n", RES); break; #define CALL_FUNC(__func__) {\ beval += Dyn_EvalOp(ded, bytecode, CO);\ RES = __func__(RES); \ break; \ } case FINT: CALL_FUNC(floorf) case FABS: CALL_FUNC(fabsf) case FSIN: CALL_FUNC(sinf) case FCOS: CALL_FUNC(cosf) case FTAN: CALL_FUNC(tanf) case FASIN: CALL_FUNC(asinf) case FACOS: CALL_FUNC(acosf) case FATAN: CALL_FUNC(atanf) case FSQR: { beval += Dyn_EvalOp(ded, bytecode, CO); RES = RES*RES; break; } case FSQRT: CALL_FUNC(sqrtf) case FLOG: CALL_FUNC(logf) case FLOG10: CALL_FUNC(log10f) #undef CALL_FUNC case FSIGN: { beval += Dyn_EvalOp(ded, bytecode, CO); if (RES > 0.0f) RES = 1.0f; else if (RES < 0.0f) RES = -1.0f; break; } case FPOW: { float r1; beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES; beval += Dyn_EvalOp(ded, bytecode, CO); RES = powf(r1,RES); break; } case FMAX: { float r1; beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES; beval += Dyn_EvalOp(ded, bytecode, CO); RES = r1 > RES ? r1 : RES; break; } case FMIN: { float r1; beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES; beval += Dyn_EvalOp(ded, bytecode, CO); RES = r1 < RES ? r1 : RES; break; } case FRANDOM: { #ifdef RNG_ISO RES = (float)rand()/RAND_MAX; #endif #ifdef RNG_BSD RES = (float)random()/RAND_MAX; #endif #ifdef RNG_SVID RES = drand48(); #endif break; } case FVLENGTH:{ float r1; beval += Dyn_EvalOp(ded, bytecode, CO); r1 = RES; beval += Dyn_EvalOp(ded, bytecode, CO); RES = sqrtf(r1*r1 + RES*RES); break; } case FVANGLE:{ float x,y; float ang = 0.0f; beval += Dyn_EvalOp(ded, bytecode, CO); x = RES; beval += Dyn_EvalOp(ded, bytecode, CO); y = RES; if (y > 0.0f){ if (x > 0.0f) ang = atanf(y/x); else if (x < 0.0f) ang = M_PI + atanf(y/x); else ang = M_PI_2; } else if (y <= 0.0f){ if (x < 0.0f) ang = M_PI + atanf(y/x); else if (x > 0.0f) ang = M_PI*2.0f + atanf(y/x); else ang = M_PI_2*3.0f; } RES = ang; break; } case FDATA_OSC:{ int channel, sample; beval += Dyn_EvalOp(ded, bytecode, CO); channel = (int)RES; beval += Dyn_EvalOp(ded, bytecode, CO); sample = (int)RES; if ((sample >= 0) && (sample < 512)){ if ((channel == 1) || (channel == 2)) RES = ded->d->data_osc[channel-1][sample]; else if (channel == 0){ RES = (ded->d->data_osc[0][sample] + ded->d->data_osc[1][sample]) * 0.5f; } else RES = 0.0f; } else RES = 0.0f; break; } case FDATA_FREQ:{ int channel, band; beval += Dyn_EvalOp(ded, bytecode, CO); channel = (int)RES; beval += Dyn_EvalOp(ded, bytecode, CO); band = (int)RES; if ((band >= 0) && (band < 256)){ if ((channel == 1) || (channel == 2)) RES = ded->d->data_freq[channel-1][band]; else if (channel == 0){ RES = (ded->d->data_freq[0][band] + ded->d->data_freq[1][band]) * 0.5f; } else RES = 0.0f; } else RES = 0.0f; break; } /* * * Variables handling * */ #define VAR_ASSIGN(__op__) { \ int vn = bytecode[CO].i; \ beval++; \ beval += Dyn_EvalOp(ded, bytecode, CO); \ *(GET_VAR_PTR(ded->d, vn)) __op__ RES; \ break; \ } case VAR_SET: VAR_ASSIGN(=) case VAR_SET_PLUS: VAR_ASSIGN(+=) case VAR_SET_MIN: VAR_ASSIGN(-=) case VAR_SET_DIV: VAR_ASSIGN(/=) case VAR_SET_MUL: VAR_ASSIGN(*=) #undef VAR_ASSIGN #define VARARR_ASSIGN(__op__) { \ int arri = bytecode[CO].i; \ int i; \ int idx, mlt; \ int fail = 0; \ beval++; \ \ idx = 0; \ mlt = 1; \ for (i=0;id->user_arr_desc[arri].dcnt;i++){ \ int dm = ded->d->user_arr_desc[arri].dims[i]; \ int rx; \ \ beval += Dyn_EvalOp(ded, bytecode, CO); \ rx = (int)RES; \ \ if ((rx < 0) || (rx >= dm)){ \ eprintf("array index out of bounds\n"); \ fail = 1; \ break; \ } \ idx += mlt * rx; \ mlt *= dm; \ } \ \ if (!fail){ \ beval += Dyn_EvalOp(ded, bytecode, CO); \ /*printf("array setting: %d[%d] to %f\n", arri, idx, RES);*/ \ ded->d->user_arr_desc[arri].data[idx] __op__ RES; \ } \ break; \ } case VARARR_SET: VARARR_ASSIGN(=) case VARARR_SET_PLUS: VARARR_ASSIGN(+=) case VARARR_SET_MIN: VARARR_ASSIGN(-=) case VARARR_SET_DIV: VARARR_ASSIGN(/=) case VARARR_SET_MUL: VARARR_ASSIGN(*=) #undef VARARR_ASSIGN case VARRAY:{ int arri = bytecode[CO].i; int i; int idx, mlt; int fail = 0; beval++; idx = 0; mlt = 1; for (i=0;id->user_arr_desc[arri].dcnt;i++){ int dm = ded->d->user_arr_desc[arri].dims[i]; float rx; beval += Dyn_EvalOp(ded, bytecode, CO); rx = RES; if ((rx < 0) || (rx >= dm)){ eprintf("array index out of bounds\n"); fail = 1; break; } idx += mlt * ((int)rx); mlt *= dm; } if (!fail){ /*printf("array get: %d[%d]\n", arri, idx);*/ RES = ded->d->user_arr_desc[arri].data[idx]; } else RES = 0.0f; break; } /* * * */ case FGBEGIN:{ int what; beval += Dyn_EvalOp(ded, bytecode, CO); what = (int)RES; if (!ded->d->glstate.enabled){ eprintf("You can not use 'Begin' in this code section\n"); RES = 0.0f; break; } /* check if we called only once */ if (ded->d->glstate.begin != 0){ eprintf("'Begin' multiple calls\n"); RES = 0.0f; break; } switch (what){ case GL_POINTS: case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUADS: case GL_QUAD_STRIP: case GL_POLYGON: sc_glBegin(what); ded->d->glstate.begin++; break; default: eprintf("invalid 'begin' type: %f\n", RES); } break; } case FGEND:{ if (!ded->d->glstate.enabled){ eprintf("You can not use 'End' in this code section\n"); RES = 0.0f; break; } if (ded->d->glstate.begin != 0){ sc_glEnd(); ded->d->glstate.begin = 0; } else eprintf("'End' without 'Begin'\n"); RES = 0.0f; break; } case FGVERTEX:{ float x, y; beval += Dyn_EvalOp(ded, bytecode, CO); x = RES; beval += Dyn_EvalOp(ded, bytecode, CO); y = RES; if (!ded->d->glstate.enabled){ eprintf("You can not use 'Vertex' in this code section\n"); RES = 0.0f; break; } if (ded->d->glstate.begin != 0){ sc_glVertex2f(x, y); } else eprintf("'Vertex' without 'Begin'\n"); RES = 0.0f; break; } case FGCOLOR:{ float c[4]; beval += Dyn_EvalOp(ded, bytecode, CO); c[0] = RES; beval += Dyn_EvalOp(ded, bytecode, CO); c[1] = RES; beval += Dyn_EvalOp(ded, bytecode, CO); c[2] = RES; beval += Dyn_EvalOp(ded, bytecode, CO); c[3] = RES; if (!ded->d->glstate.enabled){ eprintf("You can not use 'Color' in this code section\n"); RES = 0.0f; break; } if (ded->d->glstate.begin != 0){ sc_glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c); } else eprintf("'Color' without 'Begin'\n"); RES = 0.0f; break; } /* * * */ case STM_FOR:{ int bpos, cpos; int len_body = bytecode[CO].i; int len_postl = bytecode[CO+1].i; int len_cond; int i, elen; beval += 2; /* loop init */ beval += Dyn_EvalOp(ded, bytecode, CO); /* loop condition */ cpos = beval; len_cond = Dyn_EvalOp(ded, bytecode, COO(cpos)); bpos = beval+len_cond; if ((int)RES){ do { /* loop body */ for (i=0;id, opcode); if (fct){ RES = *fct; } else { /* something is very bad */ if (IS_VAR_INTERN(opcode) || IS_VAR_USER(opcode)){ eprintf("Invalid variable number %d-%d\n", opcode, VINTVAR); eprintf("Warning: code at: %p:%d\n", bytecode, CO); interpreter_ice(2, opcode, VINTVAR, CO); /*exit(1);*/ } else { eprintf("Warning: unhandled opcode: %d\n", opcode); eprintf("Warning: code at: %p:%d\n", bytecode, CO); interpreter_ice(1, opcode, CO, 0); /*exit(1);*/ } return beval; } } } return beval; } static int Dyn_Evaluator(DynamicsData *d, Code *bytecode, int codelen, float *res) { struct Dyn_EvalOp_Data ded; int c = 0; ded.d = d; ded.res = 0.0f; ded.codelen = codelen; ded.flags = FLAGS_NONE; /*dprintf("evaluating %p len %d \n", bytecode, codelen);*/ while (c < codelen) c += Dyn_EvalOp(&ded, bytecode, c); return 0; } static int scivi_dyn_add_intern_variable(DynamicsData *d, char *vn, float *contr) { int i = d->intern_vars_last_ind; void *p; if (i == (VINTVAR_LAST-VINTVAR)){ eprintf("ICE: Out of variable storage space!\n"); return -1; } if (i == d->intern_vars_count){ eprintf("WARNING: increasing internal variables buffer\n"); d->intern_vars_count += 128; if (d->intern_vars_count > (VINTVAR_LAST-VINTVAR)) d->intern_vars_count = (VINTVAR_LAST-VINTVAR); p = realloc(d->intern_vars_desc, sizeof(VarDescription)*d->intern_vars_count); if (p==NULL){ eprintf("Failed to reallocate %d bytes\n", sizeof(VarDescription)*d->intern_vars_count); return -1; } d->intern_vars_desc = (VarDescription*)p; } /* keep dmalloc happy */ p = malloc(strlen(vn)+1); if (p == NULL){ eprintf("Failed to allocate %d bytes\n", strlen(vn)+1); return -1; } strcpy(p, vn); d->intern_vars_desc[i].varname = p; d->intern_vars_desc[i].num.p = contr; d->intern_vars_last_ind++; return i; } int scivi_dyn_declare_variable(DynamicsData *d, char *vn) { int i = d->user_vars_last_ind; void *p; if (i == (VUSER_LAST-VUSER)){ eprintf("Out of variable storage space!"); return -1; } if (i == d->user_vars_count){ d->user_vars_count += 512; if (d->user_vars_count > (VUSER_LAST-VUSER)) d->user_vars_count = (VUSER_LAST-VUSER); p = realloc(d->user_vars_desc, sizeof(VarDescription)*d->user_vars_count); if (p==NULL){ eprintf("Failed to reallocate %d bytes\n", sizeof(VarDescription)*d->user_vars_count); return -1; } d->user_vars_desc = (VarDescription*)p; } /* keep dmalloc happy */ p = malloc(strlen(vn)+1); if (p == NULL){ eprintf("Failed to allocate %d bytes\n", strlen(vn)+1); return -1; } strcpy(p, vn); d->user_vars_desc[i].varname = p; d->user_vars_desc[i].num.f = 0.0f; d->user_vars_last_ind++; return VUSER+i; } int scivi_dyn_declare_array(DynamicsData *d, char *aname, int *dims, int dimscnt) { int i = d->user_arr_last_ind; void *p; int idx, tcnt; double dcnt; float *data; for (idx=0; idxuser_arr_last_ind; idx++){ if (!strcmp(d->user_arr_desc[idx].arrname, aname)){ eprintf("Array '%s' already decared\n", aname); return -2; } } if (i == d->user_arr_count){ d->user_arr_count += 128; p = realloc(d->user_arr_desc, sizeof(ArrayDescription)*d->user_arr_count); if (p==NULL){ eprintf("Failed to reallocate %d bytes\n", sizeof(ArrayDescription)*d->user_arr_count); return -1; } d->user_arr_desc = (ArrayDescription*)p; } /* keep dmalloc happy */ p = malloc(strlen(aname)+1); if (p == NULL){ eprintf("Failed to allocate %d bytes\n", strlen(aname)+1); return -1; } strcpy(p, aname); /* FIXME: handle overflows CAREFULLY!!! */ dcnt = 1; for (idx=0;idx INT_MAX)){ eprintf("Array '%s' is way too big!\n", aname); free(p); return -1; } tcnt = (int)dcnt; data = malloc(sizeof(float)*tcnt); if (data == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(float)*tcnt); free(p); return -1; } memset(data, 0, sizeof(float)*dcnt); d->user_arr_desc[i].arrname = p; d->user_arr_desc[i].dcnt = dimscnt; d->user_arr_desc[i].dims = dims; d->user_arr_desc[i].data = data; /*eprintf("set up array name '%s', index %d, floats: %d\n", aname, i, fcnt);*/ d->user_arr_last_ind++; return 0; } static int scivi_dyn_declare_function(DynamicsData *d, char *fn, int opcode, int argc) { int i = d->funcs_last_ind; if (i == d->funcs_count){ eprintf("Out of function storage space!"); return -1; } d->funcs[i].funcname = fn; d->funcs[i].funcopcode = opcode; d->funcs[i].argcount = argc; d->funcs_last_ind++; return i; } extern int mathlineno; static int CompileCode(DynamicsData *d, const char *str, int codelen, int lineno_offs, Code **code, int *csize, const char *var_prefix) { extern math_expr_cont *math_lex_expr_cont; YY_BUFFER_STATE lexbuf; math_expr_cont cont; struct math_expr *expr; int codesize; int codepos; int i; int parse_res; float res; void *p; int failure = 0; int bc; if ((!str) || (codelen <= 0)){ (*csize) = 0; (*code) = NULL; return 0; } memset(&cont, 0, sizeof(math_expr_cont)); cont.dyn_data = d; mathlineno = lineno_offs; lexbuf = math_scan_bytes(str, codelen); math_lex_expr_cont = &cont; parse_res = mathparse(&cont); math_delete_buffer(lexbuf); codepos = 0; /* starting buffer size. will be enlarged if needed */ codesize = 256; (*code) = (Code*)malloc(sizeof(Code)*codesize); if ((*code) == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(Code)*codesize); MATH(expr_cont_free)(&cont); return 1; } expr = cont.first; bc = MATH(expr_to_opcodes)(d, code, &codesize, codepos, expr, var_prefix); #if 0 dprintf("=== Code dump ===\n"); dprintf("len: %d\n", bc); for (i=0;i 0){ p = realloc(*code,sizeof(Code)*codepos); if (p != NULL){ *code = p; } else eprintf("failed to realloc %d to %d bytes. strange.\n", sizeof(Code)*codesize, sizeof(Code)*codepos); } else { free(*code); *code = NULL; (*csize) = 0; } dprintf("compiled code at %p, size: %d\n", *code, *csize); return 0; } DynamicsData *scivi_dyn_data_init() { DynamicsData *d; d = (DynamicsData *)malloc(sizeof(DynamicsData)); if (d == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(DynamicsData)); return NULL; } /* initialize rng */ #ifdef RNG_ISO srand(time(0)); #endif #ifdef RNG_BSD srandom(time(0)); #endif #ifdef RNG_SVID srand48(time(0)); #endif /* FIXME/TODO free memory on oom */ d->intern_vars_last_ind = 0; d->intern_vars_count = 128; d->intern_vars_desc = (VarDescription*) malloc(sizeof(VarDescription)*d->intern_vars_count); if (d->intern_vars_desc == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(VarDescription)*d->intern_vars_count); return NULL; } d->user_vars_last_ind = 0; d->user_vars_count = 512; d->user_vars_desc = (VarDescription*) malloc(sizeof(VarDescription)*d->user_vars_count); if (d->user_vars_desc == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(VarDescription)*d->user_vars_count); return NULL; } d->funcs_last_ind = 0; d->funcs_count = 128; d->funcs = (FuncDescription*)malloc(sizeof(FuncDescription)*d->funcs_count); if (d->funcs == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(FuncDescription)*d->funcs_count); return NULL; } d->user_arr_last_ind = 0; d->user_arr_count = 128; d->user_arr_desc = (ArrayDescription*) malloc(sizeof(ArrayDescription)*d->user_arr_count); if (d->user_arr_desc == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(ArrayDescription)*d->user_arr_count); return NULL; } d->glstate.enabled = 0; d->glstate.begin = 0; #define ADD_VAR(v) \ scivi_dyn_add_intern_variable(d, #v, &d->v); ADD_VAR( starttime ); ADD_VAR( time ); ADD_VAR( frame ); ADD_VAR( width ); ADD_VAR( height ); ADD_VAR( left ); ADD_VAR( right ); ADD_VAR( top ); ADD_VAR( bottom ); ADD_VAR( mousex ); ADD_VAR( mousey ); ADD_VAR( mousebtn1 ); ADD_VAR( mousebtn2 ); ADD_VAR( mousebtn3 ); #undef ADD_VAR #define ADD_VAR(v) \ scivi_dyn_add_intern_variable(d, #v, &d->v); \ scivi_dyn_add_intern_variable(d, "i_" #v, &d->i_##v); ADD_VAR( zoom ); ADD_VAR( rot ); ADD_VAR( cx ); ADD_VAR( cy ); ADD_VAR( dx ); ADD_VAR( dy ); ADD_VAR( sx ); ADD_VAR( sy ); ADD_VAR( ox ); ADD_VAR( oy ); ADD_VAR( decay ); ADD_VAR( ob_width ); ADD_VAR( ib_width ); #undef ADD_VAR #define ADD_VAR(v) \ scivi_dyn_add_intern_variable(d, #v "R", &d->v##R); \ scivi_dyn_add_intern_variable(d, #v "G", &d->v##G); \ scivi_dyn_add_intern_variable(d, #v "B", &d->v##B); \ scivi_dyn_add_intern_variable(d, #v "A", &d->v##A); \ scivi_dyn_add_intern_variable(d, "i_" #v "R", &d->i_##v##R); \ scivi_dyn_add_intern_variable(d, "i_" #v "G", &d->i_##v##G); \ scivi_dyn_add_intern_variable(d, "i_" #v "B", &d->i_##v##B); \ scivi_dyn_add_intern_variable(d, "i_" #v "A", &d->i_##v##A); ADD_VAR( env ); ADD_VAR( osc ); ADD_VAR( ob ); ADD_VAR( ib ); #undef ADD_VAR /* Prer Pixel variables */ #define ADD_VAR(v) \ scivi_dyn_add_intern_variable(d, #v, &d->v); ADD_VAR( ppix_x ); ADD_VAR( ppix_y ); ADD_VAR( ppix_cx ); ADD_VAR( ppix_cy ); ADD_VAR( ppix_dx ); ADD_VAR( ppix_dy ); ADD_VAR( ppix_sx ); ADD_VAR( ppix_sy ); ADD_VAR( ppix_zoom ); ADD_VAR( ppix_rot ); ADD_VAR( ppix_rad ); ADD_VAR( ppix_ang ); /* Oscillator variables */ ADD_VAR( osc_look ); ADD_VAR( osc_look_param1 ); ADD_VAR( osc_look_param2 ); ADD_VAR( osc_additive ); ADD_VAR( osc_resolution ); ADD_VAR( osc_type ); ADD_VAR( osc_angle ); ADD_VAR( osc_size ); ADD_VAR( osc_amplitude ); /* Misc variables */ ADD_VAR( tex_wrap ); ADD_VAR( tex_invert ); ADD_VAR( tex_solarize ); ADD_VAR( opt_wireframe ); #undef ADD_VAR scivi_dyn_add_intern_variable(d, "beat", &d->freqs.beat); scivi_dyn_add_intern_variable(d, "bass", &d->freqs.attq[0]); scivi_dyn_add_intern_variable(d, "mid", &d->freqs.attq[1]); scivi_dyn_add_intern_variable(d, "treble", &d->freqs.attq[2]); scivi_dyn_add_intern_variable(d, "bass_max", &d->freqs.maxf[0]); scivi_dyn_add_intern_variable(d, "mid_max", &d->freqs.maxf[1]); scivi_dyn_add_intern_variable(d, "treble_max", &d->freqs.maxf[2]); scivi_dyn_add_intern_variable(d, "bass_att", &d->freqs.att[0]); scivi_dyn_add_intern_variable(d, "mid_att", &d->freqs.att[1]); scivi_dyn_add_intern_variable(d, "treble_att", &d->freqs.att[2]); #define DECL_CONST(_s_, _v_) \ scivi_dyn_add_intern_variable(d, _s_, &d->const_##_v_) DECL_CONST("PI", pi); DECL_CONST("E", e); DECL_CONST("SQRT2", sqrt2); DECL_CONST("POINTS", begin_points); DECL_CONST("LINES", begin_lines); DECL_CONST("LINE_STRIP", begin_line_strip); DECL_CONST("LINE_LOOP", begin_line_loop); DECL_CONST("TRIANGLES", begin_triangles); DECL_CONST("TRIANGLE_STRIP", begin_triangle_strip); DECL_CONST("TRIANGLE_FAN", begin_triangle_fan); DECL_CONST("QUADS", begin_quads); DECL_CONST("QUAD_STRIP", begin_quad_strip); DECL_CONST("POLYGON", begin_polygon); #undef DECL #define ADD_FUNC(n,o) \ scivi_dyn_declare_function(d, n, o, 0); ADD_FUNC("reset", FRESET_TO_DEFAULTS); ADD_FUNC("random", FRANDOM); #undef ADD_FUNC #define ADD_FUNC(n,o) \ scivi_dyn_declare_function(d, n, o, 1); ADD_FUNC("dprint", FDEBUG_PRINT); ADD_FUNC("int", FINT); ADD_FUNC("abs", FABS); ADD_FUNC("sin", FSIN); ADD_FUNC("cos", FCOS); ADD_FUNC("tan", FTAN); ADD_FUNC("asin", FASIN); ADD_FUNC("acos", FACOS); ADD_FUNC("atan", FATAN); ADD_FUNC("sqr", FSQR); ADD_FUNC("sqrt", FSQRT); ADD_FUNC("log", FLOG); ADD_FUNC("log10", FLOG10); ADD_FUNC("sign", FSIGN); #undef ADD_FUNC #define ADD_FUNC(n,o) \ scivi_dyn_declare_function(d, n, o, 2); ADD_FUNC("pow", FPOW); ADD_FUNC("min", FMIN); ADD_FUNC("max", FMAX); ADD_FUNC("vlength", FVLENGTH); ADD_FUNC("vangle", FVANGLE); ADD_FUNC("data_osc", FDATA_OSC); ADD_FUNC("data_freq", FDATA_FREQ); #undef ADD_FUNC #define ADD_FUNC(n,o,c) \ scivi_dyn_declare_function(d, n, o, c); /* graphical functions */ ADD_FUNC("Begin", FGBEGIN, 1); ADD_FUNC("End", FGEND, 0); ADD_FUNC("Vertex", FGVERTEX, 2); ADD_FUNC("Color", FGCOLOR, 4); #undef ADD_FUNC /* "special" functions */ scivi_dyn_declare_function(d, SETUP_ARRAY_FUNC_NAME, NOP, 0); d->starttime = 0.0f; d->time = 0.0f; d->frame = 0.0f; d->code_perFrame = NULL; d->code_perPixel = NULL; d->code_postFrame = NULL; load_dynamics_defaults(d); return d; } static int dyn_init_code(DynamicsData *d, const char *code_init, const int len_init, const int loffs_init, const char *code_perframe, const int len_perframe, const int loffs_perframe, const char *code_perpixel, const int len_perpixel, const int loffs_perpixel, const char *code_postframe, const int len_postframe, const int loffs_postframe) { int initcode_len, i; Code *initcode; float res; if (d->code_perFrame) free(d->code_perFrame); if (d->code_perPixel) free(d->code_perPixel); if (d->code_postFrame) free(d->code_postFrame); /* discard user variables and arrays */ if (d->user_vars_desc){ for (i=0;iuser_vars_last_ind;i++){ free(d->user_vars_desc[i].varname); d->user_vars_desc[i].varname = NULL; } } d->user_vars_last_ind = 0; if (d->user_arr_desc){ for (i=0;iuser_arr_last_ind;i++){ free(d->user_arr_desc[i].arrname); free(d->user_arr_desc[i].dims); free(d->user_arr_desc[i].data); } } d->user_arr_last_ind = 0; dprintf("parsing initial data\n"); if (CompileCode(d, code_init, len_init, loffs_init, &initcode, &initcode_len, "i_")) eprintf("Initialization code compilation failed.\n"); if (initcode && (initcode_len > 0)) Dyn_Evaluator(d, initcode, initcode_len, &res); #if !DUMP_BYTECODE free(initcode); #endif dprintf("parsing per frame data\n"); if (CompileCode(d,code_perframe, len_perframe, loffs_perframe, &(d->code_perFrame), &(d->code_perFrame_len), NULL)) eprintf("Per-frame code compilation failed.\n"); dprintf("parsing per pixel data\n"); if (CompileCode(d,code_perpixel, len_perpixel, loffs_perpixel, &(d->code_perPixel), &(d->code_perPixel_len), "ppix_")) eprintf("Per-pixel code compilation failed.\n"); dprintf("parsing post frame data\n"); if (CompileCode(d,code_postframe, len_postframe, loffs_postframe, &(d->code_postFrame), &(d->code_postFrame_len), NULL)) eprintf("Post-frame code compilation failed.\n"); #if DUMP_BYTECODE { /* just4fun */ FILE *f = fopen("/tmp/scivi-uniqe-filename.bytecode.perFrame", "w+b"); if (f){ fwrite(d->code_perFrame, sizeof(Code), d->code_perFrame_len, f); fclose(f); } f = fopen("/tmp/scivi-uniqe-filename.bytecode.perPixel", "w+b"); if (f){ fwrite(d->code_perPixel, sizeof(Code), d->code_perPixel_len, f); fclose(f); } f = fopen("/tmp/scivi-uniqe-filename.bytecode.postFrame", "w+b"); if (f){ fwrite(d->code_postFrame, sizeof(Code), d->code_postFrame_len, f); fclose(f); } f = fopen("/tmp/scivi-uniqe-filename.bytecode.init", "w+b"); if (f){ fwrite(initcode, sizeof(Code), initcode_len, f); fclose(f); } } #endif return 0; } int scivi_dyn_init_code_from_strings(DynamicsData *d, const char *code_init, const char *code_perframe, const char *code_perpixel, const char *code_postframe) { #define LEN(b) (((b) != NULL) ? strlen((b)) : 0) return dyn_init_code(d, code_init, LEN(code_init), 1, code_perframe, LEN(code_perframe), 1, code_perpixel, LEN(code_perpixel), 1, code_postframe, LEN(code_postframe), 1); #undef LEN } int scivi_dyn_init_code(DynamicsData *d, PresetInfo *p) { return dyn_init_code(d, p->init, p->init_clen, p->init_lineoffs, p->pframe, p->pframe_clen, p->pframe_lineoffs, p->ppixel, p->ppixel_clen, p->ppixel_lineoffs, p->postframe, p->postframe_clen, p->postframe_lineoffs); } void scivi_dyn_data_finit(DynamicsData *d) { int i; if (!d) return; if (d->user_vars_desc){ for (i=0;iuser_vars_last_ind;i++){ free(d->user_vars_desc[i].varname); } free(d->user_vars_desc); d->user_vars_desc = NULL; } if (d->intern_vars_desc){ for (i=0;iintern_vars_last_ind;i++){ free(d->intern_vars_desc[i].varname); } free(d->intern_vars_desc); d->intern_vars_desc = NULL; } if (d->user_arr_desc){ for (i=0;iuser_arr_last_ind;i++){ free(d->user_arr_desc[i].arrname); free(d->user_arr_desc[i].dims); free(d->user_arr_desc[i].data); } free(d->user_arr_desc); d->user_arr_desc = NULL; } if (d->funcs){ free(d->funcs); d->funcs = NULL; } if (d->code_perFrame) free(d->code_perFrame); if (d->code_perPixel) free(d->code_perPixel); if (d->code_postFrame) free(d->code_postFrame); free(d); } void scivi_dyn_pixel_process(DynamicsData *d, float x, float y, float *nx, float *ny) { float rad = sqrt(x*x + y*y); float ang = 0.0f; float tx,ty; float res; float rot_sin, rot_cos; float a1; if (y > 0.0f){ if (x > 0.0f) ang = atanf(y/x); else if (x < 0.0f) ang = M_PI + atanf(y/x); else ang = M_PI_2; } else if (y <= 0.0f){ if (x < 0.0f) ang = M_PI + atanf(y/x); else if (x > 0.0f) ang = M_PI*2.0f + atanf(y/x); else ang = M_PI_2*3.0f; } d->ppix_x = x; d->ppix_y = y; d->ppix_cx = d->cx; d->ppix_cy = d->cy; d->ppix_dx = 0.0f; d->ppix_dy = 0.0f; d->ppix_sx = 1.0f; d->ppix_sy = 1.0f; d->ppix_zoom = 1.0f; d->ppix_rot = 0.0f; d->ppix_rad = rad; d->ppix_ang = ang; if (d->code_perPixel && (d->code_perPixel_len > 0)) Dyn_Evaluator(d, d->code_perPixel, d->code_perPixel_len, &res); tx = (d->ppix_x - d->ppix_cx)/(d->ppix_zoom*d->ppix_sx) + d->ppix_dx; ty = (d->ppix_y - d->ppix_cy)/(d->ppix_zoom*d->ppix_sy) + d->ppix_dy; if (d->ppix_rot != 0.0f){ sincosf(d->ppix_rot, &rot_sin, &rot_cos); *nx = tx*rot_cos - ty*rot_sin; *ny = tx*rot_sin + ty*rot_cos; } else { *nx = tx; *ny = ty; } *nx = *nx + d->ppix_cx; *ny = *ny + d->ppix_cy; } void scivi_dyn_postframe_process(DynamicsData *d) { float res; d->glstate.enabled++; if (d->code_postFrame && (d->code_postFrame_len > 0)) Dyn_Evaluator(d, d->code_postFrame, d->code_postFrame_len, &res); if (d->glstate.begin) sc_glEnd(); d->glstate.enabled--; } void scivi_dyn_frame_process(DynamicsData *d) { float res; /* MOVEMENT */ d->dx = d->i_dx; d->dy = d->i_dy; /* CENTER OF Zoom/Rotation/Scale */ d->cx = d->i_cx; d->cy = d->i_cy; /* ZOOM */ d->zoom = d->i_zoom; /* ROTATION */ d->rot = d->i_rot; /* SCALE */ d->sx = d->i_sx; d->sy = d->i_sy; /* OSCILLATOR POSITION */ d->ox = d->i_ox; d->oy = d->i_oy; /* DECAY */ d->decay = d->i_decay; /* COLORS */ d->envR = d->i_envR; d->envG = d->i_envG; d->envB = d->i_envB; d->envA = d->i_envA; d->oscR = d->i_oscR; d->oscG = d->i_oscG; d->oscB = d->i_oscB; d->oscA = d->i_oscA; d->obR = d->i_obR; d->obG = d->i_obG; d->obB = d->i_obB; d->obA = d->i_obA; d->ob_width = d->i_ob_width; d->ibR = d->i_ibR; d->ibG = d->i_ibG; d->ibB = d->i_ibB; d->ibA = d->i_ibA; d->ib_width = d->i_ib_width; if (d->code_perFrame && (d->code_perFrame_len > 0)) Dyn_Evaluator(d, d->code_perFrame, d->code_perFrame_len, &res); }