Drawing in jitter

wijesijp's icon

I am new to max/msp jitter so I am not quite sure how to approach this problem. I hope some of you can point me in the correct direction.

I wanted to display a scene consist of some simple objects like squares, triangles, circles. Locations of these objects are provided to max by some other program and I have their location inside max/msp.

Initially I designed the entire scene using jit.gl.sketch. I send messages to it to draw these objects, and it was working fine but when the number of objects increased it became so complicated.

Then I decided to make a java external to handle this problem and I can see the entire program can be simplified.

But how do I draw something in jitter using java external? Can I draw into a jit.gl.sketch?

Can anyone tell me how something like this done

Robin Price's icon

check the thread below this one about using traer physics in mxj, it's got some sample code I made showing how to instantiate and use a jit.gl.sketch inside your mxj, it's honestly not that hard, you just render to a named texture and then bang on that back in your patcher

wijesijp's icon

I couldn't find the sample code from your blog. Could you be kind enough to post a link to the code

Robin Price's icon
wijesijp's icon

Based on your sample codes I managed to get my program working.

Now I can draw objects but how do I set a texture for it.
I can create a texture object like     
texture = new JitterObject("jit.gl.texture");
but I don't know how to set a texture to it or how to use that texture on a object
can you help?

Robin Price's icon

sorry been away for a while, did you sort this?

wijesijp's icon

Still could not get it sorted
Following is my code. Can you tell me how to load the texture from a file and then apply it to the sphere?

import com.cycling74.max.*;
import com.cycling74.jitter.*;

public class drawtest extends MaxObject
{

    JitterObject sketch;

    JitterObject texture;

    public drawtest()
    {
        declareInlets(new int[]{ DataTypes.ALL, DataTypes.ALL});
        declareOutlets(new int[]{ DataTypes.ALL, DataTypes.ALL});
        setInletAssist(new String[] { "bang to output","list from TuioClient (ID,X,Y,angle,scale,R,G,B,alpha)"});
        setOutletAssist(new String[] { "the result opengl text"});

        createInfoOutlet(false);

        sketch = new JitterObject("jit.gl.sketch");
        sketch.setAttr("drawto","draw_plane");
        sketch.setAttr("antialias", 1);
        sketch.setAttr("lighting_enable", 1);

        //texture = new JitterObject("jit.gl.texture");
        //texture.read("texture2.tif");
        //texture.setAttr("name","cloud");
        //texture.setAttr("file","texture2.tif");

    }

    public void bang()
    {
    }

    public void draw()
    {

        sketch.send("reset");

        sketch.send("glmatrixmode",new Atom[]{Atom.newAtom("projection")});
        sketch.send("glloadidentity");
        sketch.send("glortho", new Atom[]{Atom.newAtom(-50.0f),Atom.newAtom(50.0f),Atom.newAtom(50.0f),Atom.newAtom(50.0f),Atom.newAtom(-50.0f),Atom.newAtom(100.0f)});
        sketch.send("glmatrixmode",new Atom[]{Atom.newAtom("modelview")});
        sketch.send("glloadidentity");
        sketch.send("glenable",new Atom[]{Atom.newAtom("depth_test")});
        sketch.send("glshademodel",new Atom[]{Atom.newAtom("smooth")});

        sketch.send("glpushmatrix");

        sketch.send("glcolor", new float[]{1.0f,0.0f,0.5f});
        sketch.send("glscale", new float[]{0.1f,0.1f,0.1f});
        sketch.send("moveto", new float[]{0.0f,0.0f,-10.0f});

        sketch.send("sphere",1.0f);

        sketch.send("glpopmatrix");

    }

    public void notifyDeleted()
    {
        sketch.freePeer();
        texture.freePeer();
    }

}

Robin Price's icon

yo wijesijp

this applies a texture loaded with a read message but you could embed the file name in the code hope it helps

import com.cycling74.max.*;
import com.cycling74.jitter.*;

public class textureTest extends MaxObject {

    JitterObject texture;
    JitterObject gridshape;

    private static final String[] INLET_ASSIST = new String[]{
        "inlet 1 help"
    };
    private static final String[] OUTLET_ASSIST = new String[]{
        "outlet 1 help"
    };

    public textureTest(Atom[] args) {

        declareInlets(new int[]{DataTypes.ALL});
        declareOutlets(new int[]{DataTypes.ALL});

        setInletAssist(INLET_ASSIST);
        setOutletAssist(OUTLET_ASSIST);

        texture = new JitterObject("jit.gl.texture");
        texture.setAttr("drawto", "test");
        texture.setAttr("name", "tex2");

        gridshape = new JitterObject("jit.gl.gridshape");
        gridshape.setAttr("drawto", "test");
        gridshape.setAttr("shape", "plane");
        gridshape.setAttr("texture", "tex2");
        gridshape.setAttr("automatic", 1);
    }

    public void read(String s) {
        texture.send("read", new Atom[] { Atom.newAtom(s) });
    }

    public void notifyDeleted() {
        texture.freePeer();
        gridshape.freePeer();
    }

}
Max Patch
Copy patch and select New From Clipboard in Max.

wijesijp's icon

Thank you for sending this code sample. Your code is working perfectly.
Since I wanted to load the texture on the fly, I included the file name in the code.
I only add following line
texture.send("read", new Atom[] { Atom.newAtom("Forest.jpg") });
right after, texture.setAttr("name", "tex2");

And the image looks totally different. The image looks very bluish. Funny thing is if I click the bang and load the file manually it looks OK. I have included a screen shot for you to see.
Any idea what is happening?

Robin Price's icon

it looks like the plane data is being read wrong (like you're missing the red channel perhaps) or maybe they're being swapped.

i'll look in to this as I'm doing something similar at the moment.

Robin Price's icon

I have the same problem, and I can replicate it regular jitter. See here

Max Patch
Copy patch and select New From Clipboard in Max.

I think it's a bug with the way jit.gl.texture object inititializes itself, even if you just supply the name of jpg with the file attribute for a regular texture when the patch loads the texture starts out blue, you have to re-read the file for it look normal - just like in the java case. i've sent a bug report and started a thread in the jitter forums. For the moment I recommend you create you texture objects wait a while and then send the read or set the file attribute with the name of the jpg you want.

wijesijp's icon

Thanks for your help on this.
I decided to load the textures separately for the time being.
Do we have to use jit.gl.gridshape to load a texture?
Suppose I wanted to draw a sketch triangle in the same scene how do I do that?
Do you have any sample code showing loading a texture and drawing a sketch object at the same time?

Robin Price's icon

funny you should say that but I've spent all day doing just that, happy to share, this is just a code extract so you'll need to put some more stuff into it, there's no point me posting the wohle thing as it's linked to an external mysql database

public void bang() {
        physics.advanceTime(1f);
        sketch.setAttr("drawto", drawto);
        sketch.setAttr("capture", capture);
        sketch.setAttr("depth_enable", 0);
        sketch.setAttr("lighting_enable", 0);
        sketch.setAttr("antialias", 1);
        sketch.send("reset");
        sketch.send("glenable", "blend");
        sketch.send("glblendfunc", new Atom[]{ Atom.newAtom(6), Atom.newAtom(8) });
        sketch.send("glpushmatrix");
        sketch.send("gltranslate", new Atom[]{ Atom.newAtom(position[0]), Atom.newAtom(position[1]), Atom.newAtom(position[2]) });
        sketch.send("glrotate", new Atom[]{ Atom.newAtom(rotate[0]), Atom.newAtom(rotate[1]), Atom.newAtom(rotate[2]), Atom.newAtom(rotate[3]) });
        sketch.send("glscale", new Atom[]{ Atom.newAtom(scale[0]), Atom.newAtom(scale[1]), Atom.newAtom(scale[2]) });
        Iterator k = slates.values().iterator();
        while (k.hasNext()) {
            Slate s = (Slate) k.next();
            if (s.valid) {
                sketch.send("glpushattrib");
                //work out vertices
                // bottom left
                float x1 = s.p.position().x() - (0.6666f)*size;
                float y1 = s.p.position().y() - (0.5f)*size;
                float z1 = s.p.position().z();
                Atom[] v1 = new Atom[]{ Atom.newAtom(x1), Atom.newAtom(y1), Atom.newAtom(z1) };
                //bottom right
                float x2 = s.p.position().x() + (0.6666f)*size;
                float y2 = s.p.position().y() - (0.5f)*size;
                float z2 = s.p.position().z();
                Atom[] v2 = new Atom[]{ Atom.newAtom(x2), Atom.newAtom(y2), Atom.newAtom(z2) };
                //top right
                float x3 = s.p.position().x() + (0.6666f)*size;
                float y3 = s.p.position().y() + (0.5f)*size;
                float z3 = s.p.position().z();
                Atom[] v3 = new Atom[]{ Atom.newAtom(x3), Atom.newAtom(y3), Atom.newAtom(z3) };
                //top left
                float x4 = s.p.position().x() - (0.6666f)*size;
                float y4 = s.p.position().y() + (0.5f)*size;
                float z4 = s.p.position().z();
                Atom[] v4 = new Atom[]{ Atom.newAtom(x4), Atom.newAtom(y4), Atom.newAtom(z4) };
                //draw frame
                sketch.send("glbegin", "line_loop");
                sketch.send("glcolor", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(frameAlpha) });
                sketch.send("glvertex", v1);
                //sketch.send("glcolor", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(0.5) });
                sketch.send("glvertex", v2);
                //sketch.send("glcolor", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(0.5) });
                sketch.send("glvertex", v3);
                //sketch.send("glcolor", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(0.5) });
                sketch.send("glvertex", v4);
                sketch.send("glend");
                //draw links
                Iterator j = slates.values().iterator();
                while (j.hasNext()) {
                    Slate s2 = (Slate) j.next();
                    if (s.video.links.contains(s2.video.id)) {
                        //bottom left
                        float x12 = s2.p.position().x() - (0.6666f)*size;
                        float y12 = s2.p.position().y() - (0.5f)*size;
                        float z12 = s2.p.position().z();
                        Atom[] v12 = new Atom[]{ Atom.newAtom(x12), Atom.newAtom(y12), Atom.newAtom(z12) };
                        sketch.send("glcolor", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(1), Atom.newAtom(linkAlpha) });
                        sketch.send("glbegin", "lines");
                        sketch.send("glvertex", v3);
                        sketch.send("glvertex", v12);
                        sketch.send("glend");
                    }
                }
                sketch.send("glpopattrib");
                //draw textured quad
                sketch.send("glpushattrib");
                sketch.send("glenable", "texture");
                sketch.send("glbindtexture", s.textureName);
                sketch.send("glbegin", "quads");
                sketch.send("gltexcoord", new Atom[]{ Atom.newAtom(0), Atom.newAtom(0) });
                sketch.send("glvertex", v1);
                sketch.send("gltexcoord", new Atom[]{ Atom.newAtom(1), Atom.newAtom(0) });
                sketch.send("glvertex", v2);
                sketch.send("gltexcoord", new Atom[]{ Atom.newAtom(1), Atom.newAtom(1) });
                sketch.send("glvertex", v3);
                sketch.send("gltexcoord", new Atom[]{ Atom.newAtom(0), Atom.newAtom(1) });
                sketch.send("glvertex", v4);
                sketch.send("glend");
                sketch.send("gldisable", "texture");
                sketch.send("glpopattrib");

            }
        }
        sketch.send("glpopmatrix");
        outlet(0, "bang");
    }

you'll need to add your own code to create jit.gl.sketch, one thing i've noticed is that if you have to tell the sketch object everytime you draw what the context is and if you are drawing to a texture, ignore the stuff about slates, basically i'm just iterating across a hashmap that references objects containing dynamically loaded and destroyed textures.

Another thing i've noticed is that you can't seem to use sketch with gridshapes (or other ob3d objects that you can use drawobject with) and expect things to appear where you want them to, somewhere along the way the geometry gets messed up. i've posted in the jitter thread about this but no one seems interested.

the glpushattrib and popattribs are vital for getting the colours to come out right, also i only get the colours i want if i draw the texture at the end, specifying pen colours doesn't seem to mean much

i think this problem and the other one might be something to do with the order of execution of the cmd list, if it was in a patch i'd turn automatic off and send a bang to it to make sure it did everything in the right order before sending a band to the renderer. unfortunately both .send("bang"); and .bang() raise errors at the moment which is not what the jitter api says they should do. i've posted about this in another post but i've not got a response yet (i did get two other bugs noticed today though so i really shouldn't complain).

wijesijp's icon

Thanks for sending this code. I finally got my program working.
Perhaps you already know this, but I found out that you can directly send float values without using atoms. Saves lot of time in typing.
Eg
sketch.send("glscale", new float[]{ 0.1f, 0.1f, 0.1f });

Robin Price's icon

cheers wijesijp i didn't know that it will save me typing you're right

wijesijp's icon

I am now expanding my application little by little. I wanted to add blending to my application and I saw you are already doing it in the sameple code you provided.
You are using

sketch.send("glblendfunc", new Atom[]{ Atom.newAtom(6), Atom.newAtom(8) });

Where did you look up these blend function values (Atom.newAtom(6), etc. ) ?

Robin Price's icon

The glblendfunc is documented here

good luck

wijesijp's icon

Maybe I didn't ask the question properly ...

What is the blend function you are applying?
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ?
6 = GL_SRC_ALPHA ?
It is not in sketch documentation also these integer values are not in chapter 6 of red book.