diff --git a/lib/zajal/loading.rb b/lib/zajal/loading.rb index 866c083..4d8cf5b 100644 --- a/lib/zajal/loading.rb +++ b/lib/zajal/loading.rb @@ -149,6 +149,7 @@ def live_load new_code, forced # stay out of the way, you GC.disable + unglobalized_code = new_code.clone new_code = globalize_code new_code old_code = App::Internals.current_code @@ -193,15 +194,19 @@ def live_load new_code, forced # run the code begin if new_sexp.fetch("/method_add_block/method_add_arg/fcall/@ident").empty? - # no blocks are used, we're in reduced mode - Events::Internals.reset_defaults - Events::Internals.defaults_proc.call - Events::Internals.draw_proc = proc new_code - Events::Internals.current_event = :draw - Events::Internals.draw_proc.call + # no blocks are used, we're in bare mode, save contents of sketch to fbo to display later + App::Internals.state = :bare + App::Internals.frame = FBO.new do + Events::Internals.reset_defaults + Events::Internals.defaults_proc.call + Graphics.reset_frame + proc(unglobalized_code).call + end else - # blocks are used, we're in complete mode + # blocks are used, we're in complete mode, save code to procs to run later + App::Internals.state = :complete + App::Internals.frame = FBO.new # TODO support global assigns burried under if/while/etc blocks if forced or (added.fetch("/method_add_block/method_add_arg/fcall/@ident").include? "setup" or not added.fetch("/assign/var_field/@gvar").empty?) diff --git a/src/ZajalInterpreter.cc b/src/ZajalInterpreter.cc index 56cd4f2..8a34f64 100644 --- a/src/ZajalInterpreter.cc +++ b/src/ZajalInterpreter.cc @@ -34,7 +34,6 @@ ZajalInterpreter::ZajalInterpreter() { keyIsPressed = false; mouseIsPressed = false; - state = INTERPRETER_NO_SKETCH; scriptModifiedTime = 0; scriptName = NULL; @@ -47,8 +46,8 @@ ZajalInterpreter::ZajalInterpreter() { initialHeight = DEFAULT_INITIAL_HEIGHT; } -InterpreterState ZajalInterpreter::getState() { - return state; +ID ZajalInterpreter::getState() { + return SYM2ID(APP_STATE_GET); } void ZajalInterpreter::printVersion() { @@ -68,13 +67,11 @@ void ZajalInterpreter::printVersion() { } void ZajalInterpreter::run() { - state = INTERPRETER_RUNNING; ofSetupOpenGL(initialWidth, initialHeight, OF_WINDOW); ofRunApp(this); } void ZajalInterpreter::run(ofAppBaseWindow* window) { - state = INTERPRETER_RUNNING; ofSetupOpenGL(window, initialWidth, initialHeight, OF_WINDOW); ofRunApp(this); } @@ -106,16 +103,16 @@ void ZajalInterpreter::setInitialHeight(int h) { void ZajalInterpreter::setup() { ofSetDefaultRenderer(&renderer); - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { INTERNAL_SET(zj_mEvents, current_event, SYM("setup")); zj_safe_proc_call(INTERNAL_GET(zj_mEvents, setup_proc), 0); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::update() { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { INTERNAL_SET(zj_mEvents, current_event, SYM("update")); zj_safe_proc_call(INTERNAL_GET(zj_mEvents, defaults_proc), 0); @@ -129,7 +126,7 @@ void ZajalInterpreter::update() { // if no error exists, run user update method, catch runtime errors zj_safe_proc_call(INTERNAL_GET(zj_mEvents, update_proc), 0); - if(ruby_error) {state = INTERPRETER_ERROR; return; } + if(ruby_error) {APP_STATE_SET(error); return; } VALUE posthooks_ary = INTERNAL_GET(zj_mEvents, update_posthooks); VALUE* posthooks_ptr = RARRAY_PTR(posthooks_ary); @@ -149,81 +146,96 @@ void ZajalInterpreter::draw() { char* error_message_ptr, *error_class; long backtrace_length; - switch(state) { - case INTERPRETER_ERROR: - INTERNAL_SET(zj_mEvents, current_event, SYM("draw")); - // TODO stop all playing videos - - error_message = zj_safe_funcall(rb_cObject, rb_intern("process_error"), 0); - if(ruby_error) { - error_message_ptr = RSTRING_PTR(rb_obj_as_string(rb_gv_get("$!"))); - } else { - error_message_ptr = RSTRING_PTR(error_message); - } - - if(RTEST(INTERNAL_GET(zj_mApp, verbose))) { - // http://metaeditor.sourceforge.net/embed/ - last_error = rb_gv_get("$!"); - error_class = RSTRING_PTR(rb_class_path(CLASS_OF(last_error))); - error_message_ptr = RSTRING_PTR(rb_obj_as_string(last_error)); - logConsoleText("$stderr", "class = %s\n", error_class); - logConsoleText("$stderr", "message = %s\n", error_message_ptr); - - logConsoleText("$stderr", "backtrace = \n"); - backtrace = rb_attr_get(last_error, rb_intern("bt")); - backtrace_length = RARRAY_LEN(backtrace); - backtrace_ptr = RARRAY_PTR(backtrace); - for(int i=0; ibegin(); + + prehooks_ary = INTERNAL_GET(zj_mEvents, draw_prehooks); + prehooks_ptr = RARRAY_PTR(prehooks_ary); + prehooks_len = RARRAY_LEN(prehooks_ary); + + for(int i = 0; i < prehooks_len; i++) { + zj_safe_proc_call(prehooks_ptr[i], 0); + } + + // no error exists, draw next frame of user code, catch runtime errors + zj_graphics_reset_frame(); + zj_safe_proc_call(INTERNAL_GET(zj_mEvents, draw_proc), 0); + if(ruby_error) { + APP_STATE_SET(error); + } + + posthooks_ary = INTERNAL_GET(zj_mEvents, draw_posthooks); + posthooks_ptr = RARRAY_PTR(posthooks_ary); + posthooks_len = RARRAY_LEN(posthooks_ary); + + for(int i = 0; i < posthooks_len; i++){ + zj_safe_proc_call(posthooks_ptr[i], 0); + if(ruby_error) APP_STATE_SET(error); + } + + // fake continious mouse press + if(mouseIsPressed) + zj_safe_proc_call(INTERNAL_GET(zj_mEvents, mouse_pressed_proc), 3, lastMouseX, lastMouseY, lastMouseButton); + if(ruby_error) APP_STATE_IS(error); + + fbo_ptr->end(); + fbo_ptr->draw(0, 0); + + } else if(APP_STATE_IS(bare)) { + Data_Get_Struct(INTERNAL_GET(zj_mApp, frame), ofFbo, fbo_ptr); + fbo_ptr->draw(0, 0); + + } // try to update script at end of setup-update-draw loop if(nextUpdate-- == 0) updateCurrentScript(); @@ -258,19 +270,19 @@ char* ZajalInterpreter::getCurrentScriptPath() { //-------------------------------------------------------------- void ZajalInterpreter::exit() { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { // TODO convert key into symbols zj_safe_proc_call(INTERNAL_GET(zj_mEvents, exit_proc), 0); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::keyPressed (int key) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { VALUE zj_cKeyEvent = rb_const_get(rb_cObject, rb_intern("KeyEvent")); VALUE keyEvent = zj_safe_funcall(zj_cKeyEvent, rb_intern("new"), 1, INT2FIX(key)); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); if(keyIsPressed) { zj_safe_proc_call(INTERNAL_GET(zj_mEvents, key_pressed_proc), 1, keyEvent); @@ -280,19 +292,19 @@ void ZajalInterpreter::keyPressed (int key) { keyIsPressed = true; } - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::keyReleased (int key) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { VALUE zj_cKeyEvent = rb_const_get(rb_cObject, rb_intern("KeyEvent")); VALUE keyEvent = zj_safe_funcall(zj_cKeyEvent, rb_intern("new"), 1, INT2FIX(key)); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); zj_safe_proc_call(INTERNAL_GET(zj_mEvents, key_up_proc), 1, keyEvent); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); keyIsPressed = false; } @@ -301,52 +313,52 @@ void ZajalInterpreter::keyReleased (int key) { //-------------------------------------------------------------- // http://www.ruby-forum.com/topic/76498 void ZajalInterpreter::mouseMoved(int x, int y) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { zj_safe_proc_call(INTERNAL_GET(zj_mEvents, mouse_moved_proc), 2, INT2FIX(x), INT2FIX(y)); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::mouseDragged(int x, int y, int button) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { lastMouseX = INT2FIX(x); lastMouseY = INT2FIX(y); lastMouseButton = zj_button_to_symbol(button); zj_safe_proc_call(INTERNAL_GET(zj_mEvents, mouse_dragged_proc), 3, lastMouseX, lastMouseY, lastMouseButton); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::mousePressed(int x, int y, int button) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { lastMouseX = INT2FIX(x); lastMouseY = INT2FIX(y); lastMouseButton = zj_button_to_symbol(button); zj_safe_proc_call(INTERNAL_GET(zj_mEvents, mouse_down_proc), 3, lastMouseX, lastMouseY, lastMouseButton); mouseIsPressed = true; - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } //-------------------------------------------------------------- void ZajalInterpreter::mouseReleased(int x, int y, int button) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { zj_safe_proc_call(INTERNAL_GET(zj_mEvents, mouse_up_proc), 3, INT2FIX(x), INT2FIX(y), zj_button_to_symbol(button)); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); mouseIsPressed = false; } } //-------------------------------------------------------------- void ZajalInterpreter::windowResized(int w, int h) { - if(state == INTERPRETER_RUNNING) { + if(APP_STATE_IS(complete)) { zj_safe_proc_call(INTERNAL_GET(zj_mEvents, window_resized_proc), 2, INT2FIX(w), INT2FIX(h)); - if(ruby_error) state = INTERPRETER_ERROR; + if(ruby_error) APP_STATE_SET(error); } } @@ -424,9 +436,9 @@ void ZajalInterpreter::reloadScript(bool forced) { fseek(scriptFile, 0, SEEK_SET); bool mustRestart = true; - bool wasLastError = (state == INTERPRETER_ERROR); // are we recovering from an error? + bool wasLastError = (APP_STATE_IS(error)); // are we recovering from an error? - if(state == INTERPRETER_RUNNING) + if(APP_STATE_IS(complete)) lastErrorImage.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); logConsoleText("$stdout", "Reading %s (%db)\n", scriptName, (int)scriptFileSize); @@ -438,7 +450,7 @@ void ZajalInterpreter::reloadScript(bool forced) { fclose(scriptFile); zj_safe_funcall(rb_cObject, rb_intern("live_load"), 2, rb_str_new2(scriptFileContent), forced? Qtrue : Qfalse); - state = ruby_error ? INTERPRETER_ERROR : INTERPRETER_RUNNING; + if(ruby_error) APP_STATE_SET(error); free(scriptFileContent); } diff --git a/src/ZajalInterpreter.h b/src/ZajalInterpreter.h index a0add03..e883f04 100644 --- a/src/ZajalInterpreter.h +++ b/src/ZajalInterpreter.h @@ -15,12 +15,6 @@ #define DEFAULT_INITIAL_WIDTH 500 #define DEFAULT_INITIAL_HEIGHT 500 -enum InterpreterState { - INTERPRETER_NO_SKETCH, - INTERPRETER_RUNNING, - INTERPRETER_ERROR -}; - class ZajalInterpreter : public ofBaseApp { public: @@ -48,7 +42,7 @@ class ZajalInterpreter : public ofBaseApp { void updateCurrentScript(); char* getCurrentScriptPath(); - InterpreterState getState(); + ID getState(); void appendLoadPath(char* path); void setInitialWidth(int w); @@ -59,9 +53,6 @@ class ZajalInterpreter : public ofBaseApp { void logConsoleText(char* consoleName, char* format, ...); private: - // the state the interpreter is in - InterpreterState state; - // is a mouse button or key being held? used to implement key_up/mouse_down vs key_down/mouse_down bool keyIsPressed, mouseIsPressed; diff --git a/src/app.cc b/src/app.cc index bd12cf5..383782a 100644 --- a/src/app.cc +++ b/src/app.cc @@ -403,6 +403,8 @@ void Init_App() { rb_define_module_under(zj_mApp, "Internals"); INTERNAL_SET(zj_mApp, verbose, Qfalse); + INTERNAL_SET(zj_mApp, state, SYM("no_sketch")); + INTERNAL_SET(zj_mApp, frame, Qnil); rb_define_private_method(zj_mApp, "segfault", RUBY_METHOD_FUNC(zj_segfault), 0); rb_define_private_method(zj_mApp, "height", RUBY_METHOD_FUNC(zj_height), -1); diff --git a/src/graphics.cc b/src/graphics.cc index cd1d30e..079fbd6 100644 --- a/src/graphics.cc +++ b/src/graphics.cc @@ -121,6 +121,13 @@ void zj_graphics_reset_frame() { zj_typography_reset_stacked_text(); } +/* TODO figure out naming conventions! */ +VALUE zj_reset_frame(VALUE self) { + zj_graphics_reset_frame(); + + return Qnil; +} + /* TODO move this to a helper source file */ int zj_graphics_make_color(int argc, VALUE* argv, int* r, int* g, int* b, int* a) { VALUE arg1, arg2, arg3, arg4; @@ -1090,7 +1097,9 @@ VALUE zj_background(int argc, VALUE* argv, VALUE klass) { } else { /* called with arguments, change the background */ + /* TODO does combining ofBackground and ofClear break things? */ ofBackground(r, g, b); + ofClear(r, g, b, a); } @@ -1113,38 +1122,21 @@ VALUE zj_background(int argc, VALUE* argv, VALUE klass) { VALUE zj_background_auto(int argc, VALUE* argv, VALUE klass) { VALUE new_background_auto; - int argca = rb_scan_args(argc, argv, "01", &new_background_auto); + rb_scan_args(argc, argv, "01", &new_background_auto); if(IS_IN_SETUP && argc > 0) { SET_DEFAULT(background_auto, rb_ary_new3(1, new_background_auto) ); } else { - switch(argca) { - case 0: - /* called without argument, return current background auto setting */ - return _zj_background_auto; + switch(argc) { + /* called without argument, return current background auto setting */ + case 0: return ofbClearBg() ? Qtrue : Qfalse; - case 1: - if(new_background_auto == Qtrue){ - /* called with true, enable auto background */ - _zj_background_auto = new_background_auto; - ofSetBackgroundAuto(true); - - } else if(new_background_auto == Qfalse) { - /* called with false, disable auto background */ - _zj_background_auto = new_background_auto; - ofSetBackgroundAuto(false); - - } else { - rb_raise(rb_eArgError, "Expected true or false!"); - - } - break; + /* called with argument, enable/disable auto background */ + case 1: ofSetBackgroundAuto(RTEST(new_background_auto)); return Qnil; } } - - return Qnil; } /* @@ -1346,4 +1338,8 @@ void Init_Graphics() { rb_define_private_method(zj_mGraphics, "background", RUBY_METHOD_FUNC(zj_background), -1); rb_define_private_method(zj_mGraphics, "color", RUBY_METHOD_FUNC(zj_color), -1); + + /* Internal stuff */ + rb_define_method(zj_mGraphics, "reset_frame", RUBY_METHOD_FUNC(zj_reset_frame), 0); + } diff --git a/src/zajal.h b/src/zajal.h index 91cbe24..6d1f108 100644 --- a/src/zajal.h +++ b/src/zajal.h @@ -21,6 +21,9 @@ /* app */ extern VALUE zj_mApp; +#define APP_STATE_IS(s) SYM2ID(INTERNAL_GET(zj_mApp, state)) == rb_intern(#s) +#define APP_STATE_GET INTERNAL_GET(zj_mApp, state) +#define APP_STATE_SET(s) INTERNAL_SET(zj_mApp, state, SYM(#s)) /* events */ extern VALUE zj_mEvents;