Slick Forums

Discuss the Slick 2D Library
It is currently Thu May 23, 2013 8:00 pm

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Sat Feb 13, 2010 2:27 pm 
Offline

Joined: Wed Jan 20, 2010 2:46 pm
Posts: 3
I'm creating a platform shooter with Slick. I use Transform for applying translations, rotations and scaling to shapes which works nicely. But i would like to do the same with images, i.e. draw an image with the applied Transform.
Image already has methods for drawing it with rotation and scaling. Is there any way to avoid extracting the angle and scale manually out of the transformation matrix and apply it directly?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 15, 2010 9:57 pm 
Offline
Regular
User avatar

Joined: Thu Mar 12, 2009 9:52 am
Posts: 142
Location: Portugal, Lisbon
Im not sure if your asking this or something else...

Image draw calls rotation and translaction, as well as scaling.

Just ignore all Image Transformations, draw image at 0,0, no scale (that means 1x scale), and do not change rotation.

After that call directly OpenGL (via LWJGL) with:

Code:
// push the current transformation matrix to the stack
GL11.glPushMatrix();

// rotate over the Z-axis
GL11.glRotatef(rotation, 0, 0, 1);

// scale on the X an Y axis by scale
GL11.glScalef(scale,scale , 1);

// perform translation (x,y)
GL11.glTranslatef(x, y,0);

// this is YOUR IMAGE
image.draw(0,0);

// Pop the matrix so that these transformations are not applied to
// all the other images.
GL11.glPopMatrix();



GL11 means openGL commands from version 1.1, GL12 means openGL commands from version 1.2 and so on...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 17, 2010 2:10 pm 
Offline

Joined: Wed Jan 20, 2010 2:46 pm
Posts: 3
Thank you very much for your answer.
My problem is that i don't know how to apply the transformation matrix. I use the Transform class from Slick and there is a method glLoadMatrix(FloatBuffer) in the renderer. How do i feed my transform into that method?
I've got a 3x3 matrix and I need a 4x4. If i just use the float array from the Transform I get an Exception: Number of remaining buffer elements is 9, must be at least 16.
I tried some ways putting the 3x3 into 4x4 but these lead to images not being drawn.

Here is a snippet of my code:

Code:
@Override
public void render(Graphics g) {
   SGL renderer = Renderer.get();
   // how do if fill the buffer that it works?
   FloatBuffer buffer = FloatBuffer.wrap(absoluteTransform.getMatrixPosition());

   renderer.glPushMatrix();
   renderer.glLoadMatrix(buffer);
   image.draw();
   renderer.glPopMatrix();
}


Top
 Profile  
 
PostPosted: Sun Oct 23, 2011 5:16 pm 
Offline

Joined: Sun Oct 23, 2011 5:07 pm
Posts: 1
You have probably already found a solution for your problem but for anyone else out there wanting to know the answer. Here it is?

You can set the transform of the Graphics object directly and then draw the image using the no arg function Image.draw().

Something like this:

Code:
graphics.pushTransform();
graphics.translate( tx, ty );
graphics.scale( sx, sy );
graphics.rotate( 0, 0, angle ); // first two arguments are for centre of rotation
image.draw();
graphics.popTransform();


Top
 Profile  
 
PostPosted: Fri Jul 13, 2012 9:37 pm 
Offline

Joined: Sun Jun 03, 2012 10:46 am
Posts: 9
After a good deal of internet sleuthing, I believe I've got the answer to petersielje's problem. I think kostbot did not understand the question. You have a slick2d Transform object, and want to apply it to an image, not just apply a series of known rotations translations and scales.

Code:
public void render(Image image,Transform transform, Graphics g){
      float[] tm=transform.getMatrixPosition(); //get the transform matrix
      
       //pad the transform to get a 4x4 3d affine transform
      float[] toBuffer={
            tm[0],tm[3],0,tm[6],
            tm[1],tm[4],0,tm[7],
            0    ,0    ,1    ,0,
            tm[2],tm[5],0    ,1 //<-note that I have not used tm[8] here as one might expect
      };
      
      //GL11 wants a "direct" FloatBuffer, but you can only get that by creating a direct ByteBuffer
      //and then creating a FloatBuffer as a view of that ByteBuffer.
      //the ByteBuffer is allocated 16*4 bytes, because there are 16 floats and each float needs 4 bytes
      ByteBuffer bb=ByteBuffer.allocateDirect(16*4);

      //this has something to do with the default byte order setting in Java being inappropriate
      bb.order(ByteOrder.nativeOrder());

      for(float f:toBuffer){
         bb.putFloat(f);
      }
      bb.rewind();
      FloatBuffer transformBuffer=bb.asFloatBuffer();

      GL11.glPushMatrix();      
      GL11.glLoadMatrix(transformBuffer);
      image.draw();
      GL11.glPopMatrix();
      
   }


This seems to be working for me for a combination of translations, scales, and rotations.


Top
 Profile  
 
PostPosted: Sun Jul 15, 2012 6:49 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
Allocating byte buffers every frame just to rotate an image isn't very efficient, nor is the code very pretty. :)

Probably easier just to transform the points using the transform() method. You could use a Rectangle shape and map the image onto it using g.texture() or ShapeRenderer, but the following methods should be a little more performant and maybe more reliable.

Code:
   private final float[] rect = new float[8];
   
   //same functionality as Image.draw, for convenience
   public void drawImage(Image image, Transform t, Color c) {
      image.startUse();
      (c!=null ? c : Color.white).bind();
      drawImageEmbedded(image, t);
      image.endUse();
   }
   
   //same functionality as drawEmbedded -- i.e. requires startUse/endUse
   public void drawImageEmbedded(Image image, Transform t) {
      //reset our array of points to the image's bounds
      rect[0] = 0;                 //top left
      rect[1] = 0;
      rect[2] = image.getWidth();  //top right
      rect[3] = 0;
      rect[4] = image.getWidth();  //bottom right
      rect[5] = image.getHeight();
      rect[6] = 0;                 //bottom left
      rect[7] = image.getHeight();
         
      //transform the points
      t.transform(rect, 0, rect, 0, 4);
      SGL gl = Renderer.get();
      
      //get the texture coordinates for our image or sub-image
      float u = image.getTextureOffsetX();
      float v = image.getTextureOffsetY();
      float uw = image.getTextureWidth();
      float vh = image.getTextureHeight();
   
      //place each point with the texture coordinate
      gl.glTexCoord2f(u, v);
      gl.glVertex2f(rect[0], rect[1]);
      gl.glTexCoord2f(u+uw, v);
      gl.glVertex2f(rect[2], rect[3]);
      gl.glTexCoord2f(u+uw, v+vh);
      gl.glVertex2f(rect[4], rect[5]);
      gl.glTexCoord2f(u, v+vh);
      gl.glVertex2f(rect[6], rect[7]);
   }


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group