Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (499)
Games in Android Showcase (118)
games submitted by our members
Games in WIP (567)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2 3
  ignore  |  Print  
  Pixel manipulation with bufferstrategy.  (Read 6231 times)
0 Members and 1 Guest are viewing this topic.
Offline relminator
« Posted 2013-08-07 09:32:25 »

I was intrigued when I saw a post about software pixel manipulation in java so I asked about a good way to do direct buffer writes and a few peeps posted very good solutions.

I'm making a new thread so as not to derail the original.

One particular post I like was by ClickerMonkey using MemoryImageSource.

Tried it but somehow won't work.  Also tried passing null instead of screen but no luck.

Here's my code but all I get is a flashing black screen.

www.pastebin.com/0dJkLA1v


Thanks.
Offline epicpunnum

Junior Newbie


Exp: 2 years


A man with a plan.


« Reply #1 - Posted 2013-08-15 05:05:08 »

Your post seems a bit vague in it's wording. This is a bit of code to sift through and I'm away from an IDE at the moment.
Could you point me towards where you're actually trying to do pixel manipulation? Depending on what you're looking to do your answer can vary.

If you're looking to access the exact value of a pixel, getting the Raster object is very useful (WritableRaster if you're looking to actually change their values). For BufferedImages, that's really easy, just use it's getRaster() method, and it'll return it's WritableRaster.

However, dealing with BufferStrategies is different. They purposefully hide their inner workings because they perform very complex operations managing VolatileImages, keeping track of each buffer, clearing unused images, and handling optimized page-flipping or blit-buffering algorithms. For those reasons, it tries to disallow you to edit values inside of it's system. Because of this, there is really only a backdoor way of getting the BufferStrategy's raster, and that's by working through the Graphics2D class.

When performing any drawing operation, the Graphics2D class creates/gets a source and destination raster, and runs them through any of it's Composite classes to blend them together via CompositeContext.compose(). If you create your own Composite and CompositeContext subclasses, you can effectively gain legitimate access to the current BufferStrategy Raster object being used. It's hacky, but it works.

The structure I'm using below is based on the source for AlphaComposite.
Here's an example you can use:
For the Composite subclass
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
import java.awt.Composite;
import java.awt.CompositeContext;


class RasterComposite extends Composite{

  //static version kept to reduce needless instantiation
 //Composite objects really just exist to store the blending rule and other things needed to blend
 //otherwise, Composites should be immutable
 public static final RasterComposite Normal = new RasterComposite();

  //bit of a singleton pattern here, but can be extended for multiple blending rules
 public static final RasterComposite getInstance(){
    return Normal;
  }

  private RasterComposite(){}

  //this is the inherited method from Composite, that links Composite and CompositeContext
 //for our case it's not that important to consider color models or rendering hints
 //but if youd like it's just a matter of passing that stuff via constructor
 public CompositeContext createContext(ColorModel cm1, ColorModel cm2, RenderingHints hints){
    return new CompositeContext();
  }

}

For the CompositeContext subclass
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
import java.awt.CompositeContext;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;


class RasterCompositeContext extends CompositeContext{

  //this is where you should store the destination Raster
 private WritableComposite theRaster;

  //an inherited method which Graphics2D uses to blend colors
 //i believe that by default Graphics2D uses AlphaComposite.SrcOver to render, so we can redirect all rendering to that
 public void compose(Raster dstIn, Raster srcIn, WritableRaster dstOut){
    theRaster = dstOut;   //try this one, but if that doesn't work, try switching it for "theRaster = dstIn.createCompatibleWritableRaster();"
   AlphaComposite.SrcOver.compose(dstIn,srcIn,dstOut);  //this allows pixels to be rendered normally in the meantime.
 }

  //another inherited method. no objects to dispose of though
 public void dispose(){}

  //and here's how you get the raster from your new composite context
 public final WritableRaster getRaster(){
    return theRaster;
  }

  }

Viola, and that's how you get the Raster object out of a BufferStrategy, in theory at least. But depending on what you're trying to do, (like if you're trying to implement additive blending while drawing) it may just be easier to create a Composite system that does everything as part of the drawing process.

Probably another, more inefficient way of getting the pixel values is to use the Robot class and get a screen capture of your screen. This is bad because if I recall this doesn't work in fullscreen, requires access to the window's position/size, needs additional scaling math if you're scaling up (because scaling down causes loss of pixel info), and during the capture, your window must be undecorated.

Hopefully I've provided some sort of solution to your problem. Smiley

Currently designing a puzzle-horror game called SLEEP in my free time.
I also draw and animate stuff on Youtube. Cheesy
Offline BurntPizza
« Reply #2 - Posted 2013-08-15 05:26:36 »

You're both over complicating this, if I understand the question.

Direct pixel access of BufferedImage:

1  
2  
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

Changing pixels[] will automatically change img, iirc.

To pack r, g, and b into one integer to put into pixels[]:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
public static int pack(int r, int g, int b) {
   //clamp to range [0, 255]
  if (r < 0)
      r = 0;
   else if (r > 255) r = 255;
   if (g < 0)
      g = 0;
   else if (g > 255) g = 255;
   if (b < 0)
      b = 0;
   else if (b > 255) b = 255;
   
   //pack it together
  return (255 << 24) | (r << 16) | (g << 8) | (b);
}


You might not need the clamp part if you know for a fact that r, g, and b will never be outside the range 0-255.

To unpack a value from pixels[] to r, g, and b values:
1  
2  
3  
int r = (pack & 0xFF0000) >> 16;
int g = (pack & 0xFF00) >> 8;
int b = pack & 0xFF;
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Jeremy
« Reply #3 - Posted 2013-08-15 06:29:12 »

It's hacky, but it works.

Probably not that well...

If you want to do software pixel shading in a real-time render loop, you need to stop and think what you're doing if you aren't using a hardware accelerated pixel shader. Unless you have a particular reason not to, consider using LWJGL or another graphics API that provides sufficient access to hardware shader APIs.

It's incredibly slow on most systems, and every time you alter an image (without using an accelerated graphics method) you have to bring it into memory to do the software pixel operations then send it back to the GPU to be 'accelerated.'

@BurntPizza I doubt it can possibly change img by altering pixels, int is a primitive type (i.e, a value type not a reference type.)

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline nsigma
« Reply #4 - Posted 2013-08-15 12:03:11 »

Basically ignore everything @Jeremy and @ericpunnum have said.  @BurntPizza's approach is absolutely correct.

If you want to do software pixel shading in a real-time render loop, you need to stop and think what you're doing if you aren't using a hardware accelerated pixel shader.

It's quite possible to do simple pixel manipulation in a real-time software rendering loop.  You'll obviously get an order of magnitude more out of a shader, but Java ain't that slow!  The sadly defunct PulpCore worked exactly like that.

It's incredibly slow on most systems, and every time you alter an image (without using an accelerated graphics method) you have to bring it into memory to do the software pixel operations then send it back to the GPU to be 'accelerated.'
This is just not true, at least with BufferedImage.  BufferedImages are never read back from the GPU - they are always primarily stored in Java memory, and all drawing to them happens in software.  Directly manipulating the pixels is often faster than using the Graphics2D on a BufferedImage.  Just be aware of issues of image management - copy into another BufferedImage if you're only going to manipulate once and use the copy to draw to the screen.  Of course, if you're running an effect every frame, you can ignore that.

@BurntPizza I doubt it can possibly change img by altering pixels, int is a primitive type (i.e, a value type not a reference type.)

Now you really don't know what you're talking about!  Tongue  It's an int[] not an int.  Arrays are reference types.  The getData() method gives you a direct 'pointer' to the image memory.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline epicpunnum

Junior Newbie


Exp: 2 years


A man with a plan.


« Reply #5 - Posted 2013-08-15 16:59:26 »

It's me again, and I'd like to defend my particular argument.

You're both over complicating this, if I understand the question. Direct pixel access of BufferedImage:
1  
2  
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

While this is true, I didn't go into it that much because the title of this post is "Pixel manipulation with bufferstrategy." As such, I felt that it was more important to explain how it could be done with a BufferStrategy (which is the fastest method of double buffering provided by Java2D) - instead of a BufferedImage. I'll agree, it is very complicated, and can be insanely slow (pretty much halves my framerate in some cases) doing certain blending algorithms.
Quote
To unpack a value from pixels[] to r, g, and b values:
1  
2  
3  
int r = (pack & 0xFF0000) >> 16;
int g = (pack & 0xFF00) >> 8;
int b = pack & 0xFF;

Pretty sure that Raster.getPixel() performs that exact same operation under the hood, so it's not really that necessary to jump through that many hoops, when there's already a method to do it for you.

I'm not saying that my method is the fastest (especially compared to GPU-accelerated libraries like JOGL or LWJGL), or even that well designed, but for what the OP is asking - which is accessing pixels in a BufferStrategy - I have at least provided a solution to what he is asking rather than talking about getting them from BufferedImages. And to be fair, I've mostly been talking about getting the Raster, rather than how exactly to get the pixels, which from the Raster you can use plenty of different approaches.

Currently designing a puzzle-horror game called SLEEP in my free time.
I also draw and animate stuff on Youtube. Cheesy
Offline jonjava
« Reply #6 - Posted 2013-08-15 17:11:30 »

BufferStrategy is just double/triple buffering. There's no need to confuse pixel manipulation into that. They're separate things that don't rely on each other at all.

http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferStrategy.html

Offline Jeremy
« Reply #7 - Posted 2013-08-15 18:30:57 »

It's quite possible to do simple pixel manipulation in a real-time software rendering loop.  You'll obviously get an order of magnitude more out of a shader, but Java ain't that slow!  The sadly defunct PulpCore worked exactly like that.
Per pixel operations at the software level are that slow. It depends on what you mean by 'simple' but obviously it is much more practical with a lower resolution image buffer.

This is just not true, at least with BufferedImage.  BufferedImages are never read back from the GPU - they are always primarily stored in Java memory, and all drawing to them happens in software.  Directly manipulating the pixels is often faster than using the Graphics2D on a BufferedImage.  Just be aware of issues of image management - copy into another BufferedImage if you're only going to manipulate once and use the copy to draw to the screen.  Of course, if you're running an effect every frame, you can ignore that.

You're right, for bufferedimages, and with a VolatileImage it is never read back either. My description of why the operation is slow is poorly put. The reason the operation is so slow on the software level is simply due to the number of iterations and due to the fact that once you begin performing software per-pixel operations on the bufferedimage the JRE gives up trying to hardware accelerate it.

Now you really don't know what you're talking about!  Tongue  It's an int[] not an int.  Arrays are reference types.  The getData() method gives you a direct 'pointer' to the image memory.

*edit*
It seems I was reading the wrong section of the javadoc...

I didn't say int[] was a value-type, I said int was a value type. The reason I had trouble believing that code is simply because I couldn't imagine the bufferedimage object returning a reference to an internal data buffer like that - especially after also implementing setData.

But I still defend my argument since the documentation claims to return a DataBuffer, which doesn't provide access to getData like its subclass DataBufferInt - I'm not sure if that type-cast is even safe.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline jonjava
« Reply #8 - Posted 2013-08-15 18:54:13 »

http://www.java-gaming.org/user-generated-content/members/54159/pxbuf.jar

source:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
package com.heartpirates;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

public class Main extends Canvas implements Runnable {

   public final int WIDTH = 300;
   public final int HEIGHT = (WIDTH * 9) / 16;

   BufferedImage bimg = new BufferedImage(WIDTH, HEIGHT,
         BufferedImage.TYPE_INT_RGB);
   int[] pixels = ((DataBufferInt) bimg.getRaster().getDataBuffer()).getData();

   public boolean running, paused;

   public Main() {
      Dimension size = new Dimension(WIDTH, HEIGHT);
      this.setMaximumSize(size);
      this.setSize(size);
      this.setMinimumSize(size);
   }

   public void start() {
      running = true;
      paused = false;
      new Thread(this).start();
   }

   @Override
   public void run() {
      while (running) {
         if (!paused) {
            step();
            render();
            swap();
         }
         sleep();
      }
   }

   private void step() {
   }

   private void render() {
      long now = System.currentTimeMillis();
      int r = (int) (now / 2000) % 6;
      for (int i = 0; i < pixels.length; i++) {

         switch (r) {
         case 0:
            pixels[i] = (int) ((now % (i + 1)) & 0xbf8f8f);
            break;
         case 1:
            pixels[i] = (int) (now * now + i * i);
            break;
         case 2:
            pixels[i] = (int) ((now * (i + 1)) >>> 1);
            break;
         case 3:
            pixels[i] = (int) (now + (i * i));
            break;
         case 4:
            pixels[i] = (int) ((now & 0x0f0f0));
            break;
         case 5:
            pixels[i] = (int) ((now * 3 + i * i * 3) & 0xffff00);
            break;
         }
      }
   }

   private void swap() {
      BufferStrategy bs = this.getBufferStrategy();
      if (bs == null) {
         if (this.getFocusCycleRootAncestor() != null)
            this.createBufferStrategy(2);
         return;
      }

      Graphics g = bs.getDrawGraphics();

      g.drawImage(bimg, 0, 0, this.getWidth(), this.getHeight(), null);

      g.dispose();
      bs.show();
   }

   private void sleep() {
      try {
         Thread.sleep(33);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      Main game = new Main();
      JFrame frame = new JFrame();
      frame.add(game);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      frame.pack();
      frame.setVisible(true);
      game.start();
   }
}

Offline Jeremy
« Reply #9 - Posted 2013-08-15 18:56:59 »


I think the confusion here comes from that cast to a DataBufferInt, the doc doesn't provide any guarantee (that I can see) that this is a valid cast - and I imagine that if it is, they don't intend for you to design your applications like since access to an internal data buffer that describes your image is something I can image the implementers of BufferedImage tried to avoid by returning the DataBuffer rather than the more powerful sub class. Is it stated anywhere that this is a guaranteed implementation?

That's kind of a hack. It's like casting a returned InputStream (whose underlying type is an IOStream) to an OutputStream.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline jonjava
« Reply #10 - Posted 2013-08-15 19:12:19 »

[snip] and I imagine that if it is, they don't intend for you to design your applications like since access to an internal data buffer that describes your image is something I can image the implementers of BufferedImage tried to avoid by returning the DataBuffer rather than the more powerful sub class. [snip]

Well, considering that DataBuffer is an abstract class I fail to see how that could be the case.

Offline Jeremy
« Reply #11 - Posted 2013-08-15 19:14:41 »

[snip] and I imagine that if it is, they don't intend for you to design your applications like since access to an internal data buffer that describes your image is something I can image the implementers of BufferedImage tried to avoid by returning the DataBuffer rather than the more powerful sub class. [snip]

Well, considering that DataBuffer is an abstract class I fail to see how that could be the case.

That argument makes no sense. Just because it returns an abstract class doesn't mean you have the right to (safely) go around casting it to anything you want. If it does use an internal DataBufferInt - it breaks code design and stability by casting it and assuming that it will always be implemented as a DataBufferInt.

I think it is a pretty fair analogy with the IOStream

you have a class IOStream which imple,ents InputStream and OutputStream.

you have a function called getInputStream(), it returns an IOStream. They don't have a getOutputStream because you aren't guaranteed (or aren't supposed to) write to the stream.

getInputStream() promises to return a reference to an inputstream. It returns a reference to IOStream. You see that and cast it to an OutputStream and begin writing to it.

3 years later, the code is refactored and it returns some exclusively readable resource that implements inputstream. You can't possibly blame the implementing class - it never promised you that it would return an outputstream.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline nsigma
« Reply #12 - Posted 2013-08-15 19:20:53 »

RGB, ARGB and ARGB_PRE BufferedImages will always be backed by DataBufferInt, but if you're that bothered about it you can check it at runtime, or you can always build the BufferedImage from scratch to use an int[] and DataBufferInt.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Jeremy
« Reply #13 - Posted 2013-08-15 19:22:57 »

RGB, ARGB and ARGB_PRE BufferedImages will always be backed by DataBufferInt, but if you're that bothered about it you can check it at runtime, or you can always build the BufferedImage from scratch to use an int[] and DataBufferInt.

Even if that is the case it is against the fundamental design principal of OOP code - whose to say you will always have write access to that buffer? They aren't making any promises on those grounds. My implementation might use a more remote optimized cache that you can't readily write to - what then? It is explicitly not providing you direct access to write permissions and you are hacking your way to them.

I really wouldn't implement this - there are a lot of reasons for the underlying buffer to change.

That code can very easily break in later revisions of the JDK or when working on a different platform with a different jre. Don't use it.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline jonjava
« Reply #14 - Posted 2013-08-15 19:40:22 »

You're absolutely right. They'll go around radically changing old code breaking all previous applications that relied on it as opposed to building things on top of the old stuff or making completely unrelated code for new things. Just like, for example, Swing, NIO and JavaFX didn't.

In any case, if you wan't to make a game for a wide audience I suggest you use something like libGDX. Software pixel manipulation like this isn't all that useful or effective anyway comparatively.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #15 - Posted 2013-08-15 19:46:35 »

A heated discussion over nothing...

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
if(dataBuffer instanceof DataBufferInt) {
   // pixel manipulation on int[]
}
else if(dataBuffer instanceof DataBufferByte) {
   // pixel manipulation on byte[]
}
else {
   // read pixels into own int[]

   // pixel manipulation on int[]

   // write int[] back into image
}


Last but not least...
  • backed by DataBufferInt
    • BufferedImage.TYPE_INT_ARGB
    • BufferedImage.TYPE_INT_RGB
    • BufferedImage.TYPE_INT_*
  • backed by DataBufferByte
    • BufferedImage.TYPE_BYTE_GRAY
    • BufferedImage.TYPE_BYTE_BGR
    • BufferedImage.TYPE_BYTE_*
  • backed by DataBufferShort
    • BufferedImage.TYPE_USHORT_555_RGB
    • BufferedImage.TYPE_USHORT_GRAY
    • BufferedImage.TYPE_USHORT_*

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline jonjava
« Reply #16 - Posted 2013-08-15 19:49:20 »

Yeah but what if they remove the DataBufferInt class altogether?! Did you think about that? Your code will break.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #17 - Posted 2013-08-15 19:51:36 »

Yeah but what if they remove the DataBufferInt class altogether?! Did you think about that? Your code will break.
Non sense. Itis in the public API, they can't remove it.

What if they remove java.lang.Object, what will we subclass? Did you think abut that? Your code will break.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline nsigma
« Reply #18 - Posted 2013-08-15 19:51:52 »

Yeah but what if they remove the DataBufferInt class altogether?! Did you think about that? Your code will break.

Since when has anything been removed from the JDK?!  Grin

Anyway, if you build the image in reverse from an int[] you can guarantee what's backing it - such as here.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline jonjava
« Reply #19 - Posted 2013-08-15 19:54:52 »

I love it when sarcasm goes unnoticed.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #20 - Posted 2013-08-15 19:55:28 »

I love it when sarcasm goes unnoticed.
If the message about removing DataBufferInt was sarcasm, it was a really poor attempt at it.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Jeremy
« Reply #21 - Posted 2013-08-15 20:13:39 »

You're absolutely right. They'll go around radically changing old code breaking all previous applications that relied on it as opposed to building things on top of the old stuff or making completely unrelated code for new things. Just like, for example, Swing, NIO and JavaFX didn't.

In any case, if you wan't to make a game for a wide audience I suggest you use something like libGDX. Software pixel manipulation like this isn't all that useful or effective anyway comparatively.

@Riven, @JonJava you are all seriously missing the point here.

It is a protected functionality - you shouldn't be accessing it. I can't believe you could possibly argue for this. If I implemented another DataBuffer that was In a more remote location not to be readily written to, your design would break assuming it is an IO structure when it infact may not. I am not suggesting they would remove DataBufferInt, I am saying that you are accessing an internal data structure you shouldn't be accessing and the object you are violating is not written to expect this behaviour.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #22 - Posted 2013-08-15 20:14:49 »

It's public API. It's perfectly valid to take advantage of it if it's there, and provide a fallback if it's not.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Jeremy
« Reply #23 - Posted 2013-08-15 20:16:56 »

It's public API. It's perfectly valid to take advantage of it if it's there, and provide a fallback if it's not.

No it isn't - for god's sake how can you possibly argue this? You'll have to elaborate more because I cannot possibly see valid use of this. It is exactly like my IOStream analogy.

Not only are you extrapolating a promise to where it is no longer valid, but you are also accessing protected data buffers. This is very basic programming practice, I can't believe I have to argue it.

I am not going to continue to argue fact - if you can find a JRE developer that encourages this - well than I still won't be convinced until it is written into the javadoc.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline jonjava
« Reply #24 - Posted 2013-08-15 20:31:45 »

I love it when sarcasm goes unnoticed.
If the message about removing DataBufferInt was sarcasm, it was a really poor attempt at it.

It was. I thought it obvious considering my preceding post. Then again, sarcasm through text isn't always easy to spot regardless of context.

Maybe I should just stick with meme's and video clips.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #25 - Posted 2013-08-15 20:34:26 »

It is explicitly not providing you direct access to write permissions and you are hacking your way to them.
BufferedImage.getRaster() returns a WritableRaster.

It's public API. It's perfectly valid to take advantage of it if it's there, and provide a fallback if it's not.
No it isn't - for god's sake how can you possibly argue this? You'll have to elaborate more because I cannot possibly see valid use of this. It is exactly like my IOStream analogy.
Take it easy. Your IOStream analogy has nothing to do with the case at hand. If you receive a DataBuffer from a public method, you are free to use
instanceof
and take advantage of your knowlegde about a specific subclass. Just like if you are stressed for memory, you can check whether a List<?> is an ArrayList, and if so, call trimToSize() on it. This is not against OOP ideology, this is taking advantange of the strengths of OOP. You can see how the JRE libs themselves often check whether Collections/Lists implement the RandomAccess interface, and write two different implementations to speedup certain operations.

Not only are you extrapolating a promise to where it is no longer valid, but you are also accessing protected data buffers. This is very basic programming practice, I can't believe I have to argue it.
These are not protected buffers in any way, they are WritableRasters. Sure, they may disable hardware acceleration for the BufferedImage, but if you want to have per-pixel control over your image, that's a guarantee.

I am not going to continue to argue fact - if you can find a JRE developer that encourages this - well than I still won't be convinced until it is written into the javadoc.
Above concepts are in use, and observable in rt.jar / src.zip.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline davedes
« Reply #26 - Posted 2013-08-15 20:40:45 »

Jeremy --

Not sure where you've been for the last several years, but modifying the backing int[] has long been the norm for per-pixel modifications.

You must be misunderstanding the code. There is no protected access. Everything is public API and well documented.

Look at the code:

BufferedImage.getRaster() --> returns a WritableRaster object, which we know we can write to

WritableRaster.getDataBuffer() --> returns a DataBuffer -- the reason this class exists is to wrap different primitive types.

By casting it to the required type (in our case, int for TYPE_INT_ARGB), we can call getData() to access the backing array. Each DataBuffer subclass implements getData(). And it's well documented; telling us that using getData() may disable hardware acceleration on a buffered image (which is likely what you want).

Offline Jeremy
« Reply #27 - Posted 2013-08-15 20:41:39 »

It is explicitly not providing you direct access to write permissions and you are hacking your way to them.
BufferedImage.getRaster() returns a WritableRaster.

It's public API. It's perfectly valid to take advantage of it if it's there, and provide a fallback if it's not.
No it isn't - for god's sake how can you possibly argue this? You'll have to elaborate more because I cannot possibly see valid use of this. It is exactly like my IOStream analogy.
Take it easy. Your IOStream analogy has nothing to do with the case at hand. If you receive a DataBuffer from a public method, you are free to use
instanceof
and take advantage of your knowlegde about the subclass. Just like if you are stressed for memory, you can check whether a List<?> is an ArrayList, and if so, call trimToSize() on it. This is not against OOP ideology, this is taking advantange of the strengths of OOP. You can see how the JRE libs themselves often check whether Collections/Lists implement the RandomAccess interface, and write two different implementations to speedup certain operations.

Not only are you extrapolating a promise to where it is no longer valid, but you are also accessing protected data buffers. This is very basic programming practice, I can't believe I have to argue it.
These are not protected buffers in any way, they are WritableRasters. Sure, they may disable hardware acceleration for the BufferedImage, but if you want to have per-pixel control over your image, that's a guarantee.

I am not going to continue to argue fact - if you can find a JRE developer that encourages this - well than I still won't be convinced until it is written into the javadoc.
Above concepts are in use, and observable in rt.jar / src.zip.

They are protected buffers - because you don't have access to them. Returning a super class is with limited implementation IS a form of protection. Yes, they are WritableRaster but like I said, that doesn't imply they are readily accessible. Hence why WritableRaster exposes explicitly accessors to access this data - so the implementor can prepare this data instead of tearing it out without warning.

Does it surprise you that undocumented functionality is in use? Any large software platform does this - its all over the windows and linux kernel - applications have broken because they have become deprecated. The reason it isn't documented is because it is subject to change - if your implementation knows something to be true, it is totally valid to hack into it - BUT if you are not maintaining your JRE - and you are not guaranteeing yourself the same platform every run, it is completely different. That is a non-sense argument and it means nothing.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline Jeremy
« Reply #28 - Posted 2013-08-15 20:45:38 »

Jeremy --

Not sure where you've been for the last several years, but modifying the backing int[] has long been the norm for per-pixel modifications.

You must be misunderstanding the code. There is no protected access. Everything is public API and well documented.

Look at the code:

BufferedImage.getRaster() --> returns a WritableRaster object, which we know we can write to

WritableRaster.getDataBuffer() --> returns a DataBuffer -- the reason this class exists is to wrap different primitive types.

By casting it to the required type (in our case, int for TYPE_INT_ARGB), we can call getData() to access the backing array. Each DataBuffer subclass implements getData(). And it's well documented; telling us that using getData() may disable hardware acceleration on a buffered image (which is likely what you want).

That is a good point - and this is done throughout the JDK and most software library - but special note is taken of its handling in the javadoc - i.e, a promise is made. Here, no promise is made.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Online Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #29 - Posted 2013-08-15 20:53:08 »

They are protected buffers - because you don't have access to them. Returning a super class is with limited implementation IS a form of protection. Yes, they are WritableRaster but like I said, that doesn't imply they are readily accessible. Hence why WritableRaster exposes explicitly accessors to access this data - so the implementor can prepare this data instead of tearing it out without warning.

Does it surprise you that undocumented functionality is in use? Any large software platform does this - its all over the windows and linux kernel - applications have broken because they have become deprecated. The reason it isn't documented is because it is subject to change - if your implementation knows something to be true, it is totally valid to hack into it - BUT if you are not maintaining your JRE - and you are not guaranteeing yourself the same platform every run, it is completely different. That is a non-sense argument and it means nothing.
It seems you assume that I didn't provide a fallback.

DataBuffer is public API, its specification is known and will not be broken by changes in the implementation.
DataBufferInt is public API, its specification is known and will not be broken by changes in the implementation.

If public API returns a DataBuffer, and it turns out to be a DataBufferInt, we have a guarantee that it will behave like it says in the specification. If the JRE library developers want to change things behind the scenes that affects behaviour to the point that it no longer behaves like specified by DataBufferInt, they must use/create a different subtype of DataBuffer. The fallback will keep the application functional in this case, therefore the application won't be broken, like you suggested.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Pages: [1] 2 3
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Pippogeek (37 views)
2014-09-24 16:13:29

Pippogeek (29 views)
2014-09-24 16:12:22

Pippogeek (18 views)
2014-09-24 16:12:06

Grunnt (42 views)
2014-09-23 14:38:19

radar3301 (24 views)
2014-09-21 23:33:17

BurntPizza (61 views)
2014-09-21 02:42:18

BurntPizza (30 views)
2014-09-21 01:30:30

moogie (36 views)
2014-09-21 00:26:15

UprightPath (49 views)
2014-09-20 20:14:06

BurntPizza (52 views)
2014-09-19 03:14:18
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!