Basic questions regarding Obj-C + jitter dev.

    Jun 21 2010 | 4:28 pm
    Forgive the basic questions. I am finally trying my hand at some jitter external dev so bare with me:
    Are there any examples of using Obj-C with Jitter (or Max) available for me to peruse and wrap my head around? I've not been able to find any officially with the SDK, but I may be overlooking something.
    Is it within best practices to include an Obj-C/Cocoa Framework within the MXO bundle to keep everything self contained? Will Max/MSP & the mxo respect the @loader_path to load my Obj-C Framework?
    Does Max have an NSRunloop (or CFRunloop) equivalent, or do I need to provide my own thread with one in my framework? Some of the Cocoa classes I use in the framework (which I wish to leverage in Jitter) require a main, NSApplication style run loop. So far I have been firing things off to the main run loop which seems to work ok in Cocoa apps where rendering (and thus my framework) happens in a thread sans a run loop (but I know apps like that have main NSRunLoop to fall back on). This is a 'planning for the future' sort of a question, and I have no idea about the nuances of Jitter external dev, or deep Max internals.
    Now for a *really* basic question. I've set my project up using the xcconfig and changed the paths, and set my build target to be based on my xcconfig. I am getting an error when trying to build:
    /../c74support/max-includes/ext_proto.h:600:0 /../c74support/max-includes/ext_proto.h:600: error: expected declaration specifiers or '...' before numeric constant
    for : #ifndef WIN_VERSION int sprintf(char *, const char *, ...); int sscanf(const char *, const char *, ...); #endif //WIN_VERSION
    as well as
    /../c74support/jit-includes/ /../c74support/jit-includes/ error: expected ')' before 'x' /../c74support/jit-includes/ /../c74support/jit-includes/ error: expected ';' before 'void'
    for void (APIENTRY *Vertex2hNV) (GLhalfNV x, GLhalfNV y); void (APIENTRY *Vertex2hvNV) (const GLhalfNV *v);
    Im assuming this is a basic oversight for the compilation errors, but Im failing to find it. My project (right now basically a slightly tweaked seems to not have syntax or basic errors in the c files).Thanks for any help!

    • Jun 21 2010 | 5:35 pm
      Hey Vade,
      The prototypes for sprintf() and sscanf() are in ext_proto.h for ancient historical reasons. I would just comment them out, since they really don't belong there anymore. Not sure about the Jitter stuff though...
      best, Tim
    • Jun 21 2010 | 8:34 pm
      First, I would recommend sand boxing the Obj-C and the C code, and avoid including any of the max headers in your Obj-C files. Then build C functions which the C part of your code can call into the Obj-C code. This is what we do in for example.
      Second, There's no easy way to automatically load an Obj-C framework which is not in the standard Library/Frameworks or application bundle locations. You will need to load the framework and link to individual functions dynamically in such a case. A third option, if possible, would just to include all the framework source in your object's xcode project rather than using an external framework.
      We have a CFRunLoop, but to avoid complications I'd recommend designing your code so it can be called explicitly rather than via the run loop if possible. If you encounter specific troubles please let us know.
    • Jun 21 2010 | 8:56 pm
      Unfortunately it seems the run loop issue is 'required', since i am using distributed objects (for IPC) and distributed notifications (for announcing availability), and those, best I can tell require a run loop on the thread they are instantiated on. So for now, all I am doing is initting on main thread and releasing on the main thread, everything else happens 'in place' wherever its needed. The framework isolates the rest of the Obj-C, so thats 'done' per se.
      Ill check out the bundle issue when I get there, so I'm sure ill be back. Thanks for the help Tim and JKC :)
    • Jun 21 2010 | 10:43 pm
      Fo the records (and those searching and finding this thread), my earlier GL errors were due to using the wrong mach-o prefix, the non gl one. Live and learn. Use macho-gl-prefix.pch.
    • Jun 25 2010 | 4:59 am
      Hi, question regarding best practices for OB3D, and objects that just use OpenGL but do not draw.
      So, my object in question takes in a texture and does stuff with it, but does not strictly draw it. It does not need a large list of OB3D inherited attributes, like inherit_transform, depth, drawto, capture, blend_mode (etc etc).
      I am attempting to 'opt out' of the OB3D attributes in my jitter class init method:
      // setup our OB3D flags to indicate our capabilities. long ob3d_flags = JIT_OB3D_NO_MATRIXOUTPUT; // no matrix output ob3d_flags |= JIT_OB3D_NO_ROTATION_SCALE; ob3d_flags |= JIT_OB3D_NO_POLY_VARS; ob3d_flags |= JIT_OB3D_NO_FOG; ob3d_flags |= JIT_OB3D_NO_MATRIXOUTPUT; ob3d_flags |= JIT_OB3D_NO_LIGHTING_MATERIAL; ob3d_flags |= JIT_OB3D_NO_DEPTH; ob3d_flags |= JIT_OB3D_NO_COLOR;
      But it seems there are some I cannot opt out of (see above). What would be the recommended method of handling this?
      At the end of the day, what my internal object really needs is access to the jitter context fro the OB3D, and a valid texture id. I plan on eventually being able to handle "jit_matrix" methods and produce my own internal jit_gl_texture object from it to handle internally, but im not there just yet.
      Any advice would be appreciated. Thanks!
    • Jun 25 2010 | 6:47 am
      you pretty much have to live with the attributes not suppressed by the ob3d_flags.
      not sure how much of this you already know, but to get the texture id of a texture bound to your object:
      // in your draw method
      t_symbol * tex = jit_attr_getsym(x, gensym("texture"));
      if(tex && tex != _jit_sym_nothing)
        void * texture_ptr = jit_object_findregistered(tex);
      	const long glid(jit_attr_getlong(texture_ptr, gensym("glid")));
      	const long gltarget(jit_attr_getlong(texture_ptr, gensym("gltarget")));
    • Jun 25 2010 | 7:07 am
      Yup got that about the texture working, thanks Rob, and interesting about those OB3D attrs. Oh well, I can live with it :)
    • Jun 26 2010 | 11:24 pm
      The example in the SDK does not include a handler for the message jit_gl_texture, but does have a texturename attribute set up, and struc variable, as well as an internal texture (not typed t_jit_obj).
      How is it that the is able to handle jit_gl_texture messages from a object? I would like similar functionality, and according to the sample excerpt that JKC posted elsewhere, handling jit_gl_texture messages is explicitely handled via an addmethod call to example does handle jit_matrix messages. Does that encapsulate a jit_gl_texture message, or is example incomplete for brevities sake?
      Thanks for any clarification.
      Right now my object uses an internal object which I create via the same code prototype as the, but I also seem to have to explicitly handle jit_gl_texture messages via my own method. Im having one odd issue where when I start my object up fresh, I have to send an emtpy 'texturename' message in order for it to look at the internal message. I guess Im looking for a way to easily handle both and matrix input, and I dont care if I am forced to have an internal object within my object, I just want it to work and be sane.
    • Jun 27 2010 | 2:30 am
      Wait...we can use obj-c in max?
      I, too, would greatly appreciate examples.
    • Jun 27 2010 | 5:14 am
      You can program externals that leverage Obj-C, yes, because Obj-C sits on top of C...
    • Jun 27 2010 | 7:34 am
      very interesting indeed!
      @vade: a very simple(possibly lame) question: are the QC plug ins made with objective-c?,do you think it would be possible to port some quartz technologies to max by using that language?.
      as a kind of request(christmas is far away, i know!): it would be very nice if the developer documentation(java or SDK) could bring some light to the dark corners of max/msp like the use of c++(or objective-c) or implementing special language features(like interfaces on java or OOP with c++).
    • Jun 27 2010 | 4:19 pm
      efe: If you want QC in Max, check out DIPS. Yes, QC plugins are typically programmed using Obj-C, or Obj-C++.
      As for Obj-C in Max, you literally just include cocoa.h, change your object from a .c to a .m, which invokes GCC via XCode to compile as Obj-C, and call Obj-C wherever you want to, keeping in mind you need to create/dispose of NSAutoReleasePool where appropriate. As far as I can tell it pretty much just works.
      So, back on topic about the Jitter SDK, how does example in the SDK download handle messages from (aka "jit_gl_texture"? Is this something inherited from OB3D? Why is it that the code JKC posted explicitly calls 'addmethod' for that message?
    • Jun 27 2010 | 6:46 pm
      texture binding and handling of the jit_gl_texture message is handled internally by the ob3d object. this is the case with
      however, if the flag JIT_OB3D_IS_SLAB is set, the ob3d will not handle the jit_gl_texture message, and you can handle it yourself in your external. this is the case with this allows certain externals to do things like adapt texture dimensions of output textures, from multiple inlets.
      unless you are trying to handle streaming textures from multiple inlets, i would think its preferable to let the ob3d handle that message for you.
    • Jun 27 2010 | 7:58 pm
      Hi Rob. Thanks. I had inadvertently set the JIT_OB3D_IS_SLAB mask on my OB3D. Removing it now my object is able to handle jit_gl_texture messages.
      If OB3D will handle binding/texture state for me, is there a way I can set the incoming jit_gl_texture message to point to my internal object, so I can reference it internally *all the time*, So I dont have to do glGets ont he bound texture? Or do I need to use the ob3d_draw_info struct? It seems like there is no way to introspect the OB3D and query it to return the bound texture, its settings, type, etc. I know I can do that with a texture "i own", something like:
      if(jit_gl_syphon_server_instance->texture) { // get our latest texture info. GLuint texname = jit_attr_getlong(jit_gl_syphon_server_instance->texture,ps_glid); GLuint width = jit_attr_getlong(jit_gl_syphon_server_instance->texture,ps_width); GLuint height = jit_attr_getlong(jit_gl_syphon_server_instance->texture,ps_height);
      //TODO: intuit texture target / 2D vs Rect
      BOOL flip = jit_attr_getlong(jit_gl_syphon_server_instance->texture,ps_flip);
      // all of these must be > 0 if(texname && width && height) { post (" recieved texture object: %i %i %i", texname, width, height);
      if(jit_gl_syphon_server_instance->syServer) { // These context calls are probably redundant now. // try and find a context. t_jit_gl_context jit_ctx = 0;
      // jitter context jit_ctx = jit_gl_get_context(); jit_ob3d_set_context(jit_gl_syphon_server_instance);
      if(jit_ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
      // output our frame [jit_gl_syphon_server_instance->syServer publishFrameTexture:texname context:CGLGetCurrentContext() textureTarget:GL_TEXTURE_RECTANGLE_EXT imageRegion:NSMakeRect(0.0, 0.0, width, height) textureDimensions:NSMakeSize(width, height) flipped:flip]; [pool drain]; } } } } else { post("No texture!?"); }
      Im assuming that means I would have to manually handle the jit_gl_texture message and do the jitter object call equivalent of patching the external texture into my internal one ? Currently I init my own internal object similarly to the videoplane to handle matrix input, and would like to re-use that texture internally wherever I can. Whats odd is, right now, I *can* use my texture, but only if I send a 'texturename' message that is empty to my object.
      My jit_gl_texture handler looks like:
      t_jit_err jit_gl_syphon_server_jit_gl_texture(t_jit_gl_syphon_server *jit_gl_syphon_server_instance, t_symbol *s, int argc, t_atom *argv) { post("texture input");
      t_jit_object *texture;
      t_symbol *name = jit_atom_getsym(argv);
      if (name) { texture = (t_jit_object*)jit_object_findregistered(name); if (!texture) { post (" couldn't get texture object!"); return JIT_ERR_GENERIC; }
      // draw our texture the texture jit_object_method(jit_gl_syphon_server_instance->texture, s, s, argc, argv);
      // add texture to ob3d texture list jit_attr_setsym(jit_gl_syphon_server_instance,ps_texture,jit_gl_syphon_server_instance->texturename);
      } return JIT_ERR_NONE; }
      Sorry, I'm having major issues with this API, it feels really rather opaque, and seems to dislike me, I must have offended it somehow. I'm happy to send sources off list/forum to someone. Thanks again for all the help
    • Jun 28 2010 | 5:33 pm
      I'm not sure. There are two approaches that may be relevant:
      1. handle your own jit_gl_texture messages like the sample code I sent you offlist. Potentially copying them to your internally managed texture if you need to do things like guarantee rectangular textures or format type or whatever. This is probably important if you need complete control over how/when any textures are bound.
      2. Ask your object what its texture name is using standard attribute functions and then look up the texture object with jit_object_findregistered.
      t_symbol *texsym = object_attr_getsym((t_object *)x,gensym("texture"));
      if (texsym&& texsym!=_jit_sym_nothing) { t_object *texobj = jit_object_findregistered(texsym); if (texobj) { // do what you want here } }
      Hope this helps.
    • Jul 02 2010 | 1:25 pm
      I'm working with vade on this. I'm new to Max in general and the Jitter API, and still finding my way around. I have a couple of questions already.
      I'm stumped by the handling of texturename in the sample code.
      t_jit_err jit_gl_videoplane_texturename(t_jit_gl_videoplane *x, void *attr, long argc, t_atom *argv)
      	t_symbol *s=jit_atom_getsym(argv);
      	x->texturename = s;
      	if (x->texture)
      	return JIT_ERR_NONE;
      This sets the name of the internal texture to the name of the referenced texture, then sets ob3d's ps_texture to that name (and as it works as expected, I presume ob3d looks up the name and finds the referenced texture rather than the same-named internal texture).
      Setting the internal texture's name to that of the referenced texture just seems weird, and that's backed up by the error that gets posted if you do this in Max - "name xxx already in use. ob3d does not allow multiple bindings". Can someone explain what's going on here?
      My second question is... what happens when you set the ps_texture property? I can't find reference for ob3d beyond the basics in the SDK docs, which do not cover this. If we handle jit_gl_texture messages ourselves and don't set ps_texture in the handler, can we still use the texture at draw-time if we bind it ourselves? Right now, whatever we do, we draw black unless we set ps_texture to _jit_sym_nothing *after* rendering has started, with some more weirdnesses thrown in.
      Cheers, T
    • Jul 02 2010 | 5:07 pm
      This sets the name of the internal texture to the name of the referenced texture, then sets ob3d's ps_texture to that name
      actually, i think you are slightly mistaken. this message is intended merely to set the name attribute of the internal texture to the argument given. if that name argument is already bound to an existing jitter object, you will get the "name already in use" warning.
      the ob3d does not store and manage an internal texture object. it simply stores a t_symbol name reference to an existing texture object. each draw frame, ob3d checks it's texture attribute and binds the texture before the jitter object's draw method.
      you should be able to handle binding the texture yourself, but i'm not quite sure what your problems are without seeing the code.
    • Jul 02 2010 | 6:09 pm
      this message is intended merely to set the name attribute of the internal texture to the argument given
      This seems crazy.
      My understanding is that the function of the @texturename attribute is to allow the use of a thus-named texture which exists elsewhere as an input, without the need for a direct connection. I can name a texture elsewhere in my patch Daisy, set the @texturename attribute of another object to Daisy, and have Daisy used as input for that object.
      Is that right?
      In which case, my point is that setting the name of the internal texture to that passed in is usually going to lead to a naming conflict and the reason for
      if (x->texture)
      remains unclear.
      To my mind, a correct version of the above would be
      t_jit_err jit_gl_videoplane_texturename(t_jit_gl_videoplane *x, void *attr, long argc, t_atom *argv)
      	t_symbol *s=jit_atom_getsym(argv);
      	x->texturename = s;
      	return JIT_ERR_NONE;
      you should be able to handle binding the texture yourself, but i'm not quite sure what your problems are without seeing the code.
      Any pointers to useful documentation or examples beyond those in the SDK for handling textures with ob3d would be fantastic.
    • Jul 03 2010 | 9:57 pm
      This (semi-redundant) attribute exists to rename the internal texture so that it can be used by other objects. It does not exist to reference an external texture (which would result in the error message you describe). For that use the texture message. Make sense?
      If you can get us a better example of what you want to do, how you are trying to do it, and what the difficulties you are experiencing, we can offer more assistance. I assume you are simply confusing the texturename attribute with the texture attribute.
    • Jul 05 2010 | 10:51 am
      Ah, it is crazy, many apologies robtherich for my scepticism.
      This (semi-redundant) attribute exists to rename the internal texture so that it can be used by other objects.
      Yuck! Right well that's weird object encapsulation but OK... but then why does the object then do jit_attr_setsym(x,ps_texture,s) after it has set the name of its internal texture? That is not part of renaming the internal texture so that it can be used by other objects. That is setting the texture attribute... perhaps you can see where my confusion arose? Apologies if I'm just being very slow...
      I assume you are simply confusing the texturename attribute with the texture attribute.
      Sadly not that simple. Will persevere.
    • Jul 06 2010 | 1:33 pm
      So has an internal texture, which then is exploited by the standard infrastructure with the standard texture attribute name. If we rename the internal texture, we need the standard ob3d infrastructure to know what its new name is, so that the texture is bound in the standard setup.
      If the object were doing all the work with texture binding and so forth, this wouldn't be necessary, but the way it is designed is that *either* an external texture or an internal texture can be used, and all the drawing code works the same--i.e. binds the texture from the texture attribute.
      I can't imagine that this is at all related to your issues, for which you should really be looking at the examples. isn't a texture processor, or a render to texture example. It's just an example of how to create an internal texture for use on the geometry.