Slick Forums

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

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Wed May 16, 2012 6:22 pm 
Offline

Joined: Mon May 14, 2012 11:43 pm
Posts: 10
Let's say I have an image like this, with the 'center' at the bottom side:
Image

And I want to draw it to a Graphics like this:
Image

I've looked through the Image and Graphics classes and a few related ones but I don't see any way to do this. Is there a way provided in Slick?


Top
 Profile  
 
PostPosted: Thu May 17, 2012 2:19 am 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
I'm curious -- why do you need this effect?

It's too specific a feature to include in Slick. The best way to achieve this is through shaders.

You need to know a little about polar to Cartesian conversion:
http://www.youtube.com/watch?v=29VW-NAd3lA

You should also understand a little about shaders if you want to know how the following code works. That way, you can optimize it to your game rather than just blindly copy-pasting.
http://www.lighthouse3d.com/opengl/glsl/

I've written a short example here for you, using the rect2polar shader source I described in this thread.

Something to note: To account for non-power-of-two (NPOT) textures, which are pretty common in Slick games, as well as allowing getSubImage to be used, I've modified the texture coordinates using uniforms. Ideally you should be using vertex attributes, but that isn't as easy to integrate with Slick's image rendering. If all of your images for this shader are power-of-two, then you can do without the texOff/texSize uniforms, as well as their use in the shader.

PolarizeShaderTest.java
Code:
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.opengl.shader.ShaderProgram;

public class PolarizeShaderTest extends BasicGame {

   public static void main(String[] args) throws SlickException {
      new AppGameContainer(new PolarizeShaderTest(), 800, 600, false).start();
   }
   
   public PolarizeShaderTest() {
      super("Polarize Test");
   }
   
   private ShaderProgram polarizeShader;
   private Image image;
   private boolean useShader, shaderSupported;
   
   private final String VERT = "testdata/shaders/pass.vert";
   private final String FRAG = "testdata/shaders/rect2polar.frag";
   
   @Override
   public void init(GameContainer container) throws SlickException {
      container.getGraphics().setBackground(Color.gray);
      
      //create a new image
      //Slick's images will use texture unit zero by default
      image = new Image("testdata/polar.png");
      
      //if shaders are supported...
      if (ShaderProgram.isSupported()) {
         try {
            //"Strict Mode" will throw errors if we try
            //to set a uniform that does not exist
            //or isn't used in the shader. For flexibility,
            //let's turn this off.
            ShaderProgram.setStrictMode(false);
            
            //We can conveniently load a program like so:
            polarizeShader = ShaderProgram.loadProgram(VERT, FRAG);
            
            //we have to set up the uniforms tex0, texOff and texSize
            polarizeShader.bind();
            
            //this means we are sampling from our image
            polarizeShader.setUniform1i("tex0", 0);
            
            //we set up texOff/texSize to account for possible sub-regions
            //this allows us to use Image.getSubImage, or NPOT images
            float texW = image.getTextureWidth();
            float texH = image.getTextureHeight();
            float texX = image.getTextureOffsetX();
            float texY = image.getTextureOffsetY();
            polarizeShader.setUniform2f("texSize", texW, texH);
            polarizeShader.setUniform2f("texOff", texX, texY);
            
            //unbind the shader once we're done
            polarizeShader.unbind();
            
            //shader works.
            shaderSupported = true;
            useShader = true;
         } catch (SlickException e) {
            e.printStackTrace();
         }         
      }
   }
   
   @Override
   public void render(GameContainer container, Graphics g)
         throws SlickException {
      //activate the shader
      if (shaderSupported && useShader)
         polarizeShader.bind();
      
      //now anything we draw will use our polarize shader
      image.draw();
      
      //disable the shader
      if (shaderSupported && useShader)
         polarizeShader.unbind();
      
      String str = shaderSupported
            ? "Press space to toggle shader"
            : "Shaders not supported!";
      g.drawString(str, 10, 20);
   }


   @Override
   public void update(GameContainer container, int delta)
         throws SlickException {
      if (container.getInput().isKeyPressed(Input.KEY_SPACE))
         useShader = !useShader;
   }
}


pass.vert
Code:
void main() {
   gl_TexCoord[0] = gl_MultiTexCoord0;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}


rect2polar.frag
Code:
#version 120

uniform sampler2D tex0;
uniform vec2 texOff;
uniform vec2 texSize;
const float PI = 3.14159265358979323846264;

void main(void) {
   vec2 texCoord = gl_TexCoord[0].st;

   //account for Slick's Image sub-regions (and NPOT images)
   texCoord = (texCoord-texOff)/texSize;
   
   //rectangular to polar filter
   vec2 norm = (1.0 - texCoord) * 2.0 - 1.0;
   float theta = PI + atan(norm.x, norm.y);
   float r = length(norm);
   vec2 polar = 1.0 - vec2(theta/(2.0*PI), r);

   //sample the texture using the new coordinates
   vec4 color = texture2D(tex0, (polar+texOff)*texSize);
   gl_FragColor = color;
}


Top
 Profile  
 
PostPosted: Thu May 17, 2012 6:57 am 
Offline

Joined: Mon May 14, 2012 11:43 pm
Posts: 10
Well, my main reason for using Slick is to avoid something as low-level or complicated as shaders- I've had nothing but trouble with them before now.

I'm trying to get a 2D shadow effect based on images (not just polygons), something like this: http://www.reddit.com/r/gamedev/comment ... ng/c4mxaki

I've got something that works somewhat fast and still looks decent, though, just by getting collision and drawing polygons on a Graphics (and keeping the light size small). I actually have another question sort of about that: If I have, say, a 256x256 image, and I try to scale it up to 1024x1024 (by drawing it on a 1024x1024 image- tell me if that's a bad idea), it always uses nearest neighbor interpolation. Is there a way to set it to bilinear (or bicubic, if it isn't too slow)?

Thanks anyway for the shaders... I might end up having to use shaders anyway, and they'd really help!


Top
 Profile  
 
PostPosted: Thu May 17, 2012 1:54 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
You can only achieve something like that with shaders and "low-level" OpenGL. I tried implementing something similar in Slick. Unfortunately, because Slick's FBO mechanic is (currently) rather bulky, it did not yield high performance using Image and getGraphics (in the screenshot, only one of those lights is dynamic, the rest baked in). The solution is to write your own FBO binding and TEXTURE_1D handling.

Ideally Slick would have a "makeDynamicLighting" method but of course it is never that easy... :P

There are other solutions that do not rely on shaders. For example, OrangyTang's geometry shadows. Or Rpe's tile-based lighting.

Quote:
If I have, say, a 256x256 image, and I try to scale it up to 1024x1024 (by drawing it on a 1024x1024 image- tell me if that's a bad idea), it always uses nearest neighbor interpolation. Is there a way to set it to bilinear (or bicubic, if it isn't too slow)?

You can set it like so:
Code:
//set it at creation time:
img = new Image("blah.png", Image.FILTER_LINEAR);

...
//OR you can change it after creation like so:
img.setFilter(Image.FILTER_LINEAR);


You can choose between FILTER_LINEAR (bilinear) or FILTER_NEAREST (nearest neighbour). If you want a particular type of interpolation other than what's provided, you'll need to implement it yourself in shaders.


Top
 Profile  
 
PostPosted: Tue May 22, 2012 7:05 pm 
Offline

Joined: Mon May 14, 2012 11:43 pm
Posts: 10
Been a while, but I decided to try getting shaders to work this morning. Unfortunately, "org.newdawn.slick.opengl.shader.ShaderProgram" does not exist in either the nightly build or the distribution linked on the main page (http://slick.cokeandcode.com). Where can I find the branch with this feature? (It seems infinitely preferable to compiling the shader myself since I do it wrong 99% of the time...)

EDIT: I found the bitbucket repo but it doesn't include a slick.jar. Do I need to compile it?


Top
 Profile  
 
PostPosted: Tue May 22, 2012 9:18 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
Until the website is updated and the dev branch merged with main, you can see this guide to getting dev branch code:
http://slick.cokeandcode.com/wiki/doku. ... ent_branch


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: No registered users and 6 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