PGraphics2D should implement cloneable but throws exception - java

Using Java Processing, I'm trying to make a deep copy of a PGraphics2D object
PGraphics2D pg_render;
pg_render = (PGraphics2D) createGraphics(width, height, P2D);
PGraphics2D pg_postprocd = (PGraphics2D)pg_render.clone();
Which throws a CloneNotSupportedException :
Unhandled exception type CloneNotSupportedException
Yet reading the doc it seems like cloning is implemented.
I need to have two instances of the PGraphics2D objects so that I can apply post-processing effects on one and keep the other one clean for analysing motion vectors and such.

Exception
The PGraphics class does not itself implement Clonable. Rather, it extends PImage and this is the class that actually implements the Cloneable interface.
This is why your call to pg_render.clone() throws CloneNotSupportedException, since PGraphics doesn't actually support cloning (but happens to extend a class that does).
Solution
The static method below returns a clone of the input PGraphics object. It makes a new PGraphics object with createGraphics(), clones the style (style includes things like current fill colour), and finally clones the pixel buffer.
Code
static PGraphics clonePGraphics(PGraphics source) {
final String renderer;
switch (source.parent.sketchRenderer()) {
case "processing.opengl.PGraphics2D" :
renderer = PConstants.P2D;
break;
case "processing.opengl.PGraphics3D" :
renderer = PConstants.P3D;
break;
default : // secondary sketches cannot use FX2D
renderer = PConstants.JAVA2D;
}
PGraphics clone = source.parent.createGraphics(source.width, source.height, renderer);
clone.beginDraw();
clone.style(source.getStyle()); // copy style (fillColor, etc.)
source.loadPixels(); // graphics buffer -> int[] buffer
clone.pixels = source.pixels.clone(); // in's int[] buffer -> clone's int[] buffer
clone.updatePixels(); // int[] buffer -> graphics buffer
clone.endDraw();
return clone;
}

Related

Apply Void method to a Canvas Object

all:
I have created a PetCanvas class to handle an ArrayList of pets that each have their own draw method. This draw method is void and accepts a GraphicsContext object that is used to specify how the pet is drawn. The GraphicsContext object comes from the PetCanvas class that has a void method sketchPet that calls draw on each of the pets in the list. I want to use the PetCanvas object to draw the Graphics to the GUI but the compiler will not allow me to add PetCanvas.sketchPet to the root because sketchPet does not return a Node object. Any suggestions? Or any more information needed to determine a solution?
Thank you in advance.
I'm beginning to think the issue lies here:
public void sketchPets() {
if (this.drawableList.size() == 0) {
throw new IllegalArgumentException("The list has no animals to draw");
}
for (Drawable current : this.drawableList) {
current.draw(this.getGraphicsContext2D());
}
}
The current.draw line does nothing with the GraphicsContext object after it is drawn. I'm not sure how to remedy this issue if it is the cause.

How to retrieve a struct from Renderscript kernel [duplicate]

This question already has answers here:
Returning a Renderscript struct from a Renderscript kernel
(2 answers)
Closed 6 years ago.
I have a problem. I would like to retrieve a struct from a renderscript kernel. What I wanted was that I would get an input a struct element... I would modify it and then return it modified. But there is no such a way in the reflected layer. I tryied to manually deserialize the data from the buffer but I am not even able to copy the buffer to a ByteBuffer because the Allocation has validation in the copyTo on a type so I have no idea what am I supposed to do...
RenderScript supports custom elements. To create one, declare a custom typedef struct like the following one, inside a RS script:
typedef struct MyElement {
int x;
int y;
bool simpleBool;
} MyElement_t;
After the build process, a ScriptField_MyElement Java class will appear, mirroring the RS struct. You will be able to use this class to create a custom Allocation that uses your own Element:
// Declares a new Allocation, based upon the custom struct Element
Element myElement = ScriptField_MyElement.createElement(mRS);
Allocation myElementsAllocation = Allocation.createSized(mRS, myElement, 5);
// Or
Allocation myElementsAllocation = ScriptField_MyElement.create1D(mRS, sizeX).getAllocation();
You can find an example of this process inside the CustomElementExample sample project.
Also, inside the SurfaceRenderExample sample project you can see how a custom element can be used to model a mathematical structure (in this case a particle, falling with some acceleration).
Inside RenderScript scripts:
To get a custom element from an allocation:
MyElement_t el = * (MyElement_t *) rsGetElementAt(aIn, index);
To change a custom element member:
el.x = 10;
To set a custom element in an allocation:
rsSetElementAt(myAlloc, (void *)&el);
Reference: RenderScript: parallel computing on Android, the easy way
Edit:
For now, there is no direct way to copy a custom struct element to the Java side.
The CustomStructElementCopyToJava sample project provides an example of the process.
Short explanation of the example
Note: the following process is EXPERIMENTAL and not performant at all! If you plan to heavily use this process, please use the Android NDK to access the allocation.
Also, in future versions of the Android SDK, this code may break because it relies on Java reflection; some normally hidden methods can change without any notice in the Android SDK.
Let's assume using the following custom struct element:
typedef struct Point {
int x;
int y;
} Point_t;
When looking at the generated code of the struct (which can be seen, in Android Studio, by pressing CTRL+B while focusing on a ScriptField_Point element on the Java side), the following elements can be seen:
public static Element createElement(RenderScript rs) {
Element.Builder eb = new Element.Builder(rs);
eb.add(Element.I32(rs), "x");
eb.add(Element.I32(rs), "y");
return eb.create();
}
You can map the contents of the custom struct in a hacky way:
1) Define the destination byte array:
byte destinationArray[] = new byte[allocationGrayPointOrdered.getBytesSize()];
2) Use Java reflection to access the hidden Allocation.copyTo method:
private static Method getCopyToWithoutValidationMethod(){
// private void copyTo(Object array, Element.DataType dt, int arrayLen)
Method allocationHiddenCopyToMethod = null;
try {
allocationHiddenCopyToMethod = Allocation.class.getDeclaredMethod("copyTo", Object.class, Element.DataType.class, int.class);
allocationHiddenCopyToMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not find allocationHiddenCopyToMethod");
}
return allocationHiddenCopyToMethod;
}
3) Perform the copy:
// Gets reflected method
Method copyToWithoutValidationMethod = getCopyToWithoutValidationMethod();
// Tries to copy contents
try {
copyToWithoutValidationMethod.invoke(allocationGrayPointOrdered, destinationArray,
Element.DataType.UNSIGNED_8, destinationArray.length);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
4) Once the array is filled with source data, it is then possible to map its content to a human-readable struct.
// Defines the destination array
ScriptField_Point.Item mappedItems[][] = new ScriptField_Point.Item[sizeX][sizeY];
// Wraps array contents
ByteBuffer byteBuffer = ByteBuffer.wrap(destinationArray);
// Sets byte order to be Android-like
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// Iterates on every column and row
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
// Allocates a new item
ScriptField_Point.Item currentItem = new ScriptField_Point.Item();
// Calculate the offset in the source array
int currentOffset = (x + y * sizeX) * ScriptField_Point.Item.sizeof;
// Gets data from the byte array
currentItem.x = byteBuffer.getInt(currentOffset);
currentItem.y = byteBuffer.getInt(currentOffset + 4);
mappedItems[x][y] = currentItem;
}
}
For the complete explanation, please refer to the book.

Instantiate class dynamically based on some constant in Java

I am making a multiplayer game which makes heavy use of a serialisable Event class to send messages over a network. I want to be able to reconstruct the appropriate subclass of Event based on a constant.
So far I have opted for the following solution:
public class EventFactory {
public static Event getEvent(int eventId, ByteBuffer buf) {
switch (eventId){
case Event.ID_A:
return EventA.deserialise(buf);
case Event.ID_B:
return EventB.deserialise(buf);
case Event.ID_C:
return EventC.deserialise(buf);
default:
// Unknown Event ID
return null;
}
}
}
However, this strikes me as being very verbose and involves adding a new 'case' statement every time I create a new Event type.
I am aware of 2 other ways of accomplishing this, but neither seems better*:
Create a mapping of constants -> Event subclasses, and use clazz.newInstance() to instantiate them (using an empty constructor), followed by clazz.initialiase(buf) to supply the necessary parameters.
Create a mapping of constants -> Event subclasses, and use reflection to find and call the right method in the appropriate class.
Is there a better approach than the one I am using? Am I perhaps unwise to disregard the alternatives mentioned above?
*NOTE: in this case better means simpler / cleaner but without compromising too much on speed.
You can just use a HashMap<Integer,Event> to get the correct Event for the eventID. Adding or removing events is going to be easy, and as the code grows this is easy to maintain when compared to switch case solution and speed wise also this should be faster than switch case solution.
static
{
HashMap<Integer,Event> eventHandlerMap = new HashMap<>();
eventHandlerMap.put(eventId_A, new EventHandlerA());
eventHandlerMap.put(eventId_B, new EventHandlerB());
............
}
Instead of your switch statement Now you can just use :
Event event = eventHandlerMap.get(eventId);
if(event!=null){
event.deserialise(buf);
}
If you're not afraid of reflection, you could use:
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}
This solution requires that int ID_N always maps to class EventN, where N can be any String where all characters return true for the method java.lang.Character.isJavaIdentifierPart(c). Also, class EventN must define a static method called deserialize with one ByteBuffer argument that returns an Event.
You could also check if field is static before trying to get its field value. I just forget how to do that at the moment.

Is java.awt.GraphicsConfiguration thread-safe? What are the alternatives

I'm extending javax.swing.JComponent to display a variable number of tiles, which all have the same size.
If a tile needs a new appearance, a SwingWorker's doInBackground() renders a new BufferedImage for it. In done(), the image is stored and JComponent.repaint() is called, indicating the updated area and an intended delay. The overridden JComponent.paintComponent() will know what to do.
The size of the tiles can be changed via the GUI. Obvioulsy, it could happen that such a request takes place while the the SwingWorker's StateValue is PENDING or STARTED.
I don't see much sense in supporting cancel(); it complicates the code and since the actual rendering does not take very long, its effect would be minimal (or even harmful if the worker had to wait longer than it will need to execute). Rather, I would like to add efficiency and have the EDT code not start a new SwingWorker if a PENDING one exists for the same tile. Then, the SwingWorker just needs to fetch the latest settings when doInBackground() starts and check whether it should really store its result in done().
So where should the BufferedImage used by the SwingWorker be cast into existence? These seem to be the options:
Create it upfront. Drawbacks: The maximum size must be chosen because the specific size is unknown, and since paintComponent() may run concurrently, two images of maximum size must be kept for all tiles at all times (think ViewPort; a dynamic solution would only require a second image of the actually needed size for visible tiles, temporarily).
Create it when creating the SwingWorker. Drawback: The maximum size must be provided since it's unknown which size is required once doInBackground() gets fired.
Create it in the SwingWOrker. Problem: Given that JComponent.paintComponent() may have to call drawImage() often, it's advisable to use GraphicsConfiguration.createCompatibleImage() to create this image. This may break the single-threadedness limitations of AWT.
I would prefer the following, but since GraphicsConfiguration belongs to AWT, and the implementation depends on the platform, is this a safe thing to do?
...
final GraphicsConfiguration gc = this.getGraphicsConfiguration();
if ((obj.worker == null) ||
(obj.worker.getState() != SwingWorker.StateValue.PENDING)) {
obj.worker = new SwingWorker<BufferedImage, Void>() {
#Override public BufferedImage doInBackground() {
... // acquire size info via synchronised access
final BufferedImage img = gc.createCompatibleImage(...);
...
return img;
}
#Override public void done() {
if (obj.worker == this) {
obj.worker = null;
try { obj.image = this.get(); }
catch (Throwable t) { ... System.exit(1); }
Outer.this.requestTileRepaint(...);
}
}
};
obj.worker.execute();
}
...
Clarification
Looking at the above code, one might argue that there is no real muti-threading issue with this solution, since the GraphicsConfiguration object is created on the EDT exclusively for this particular worker. However,
I was looking at the abstract class implementation and it contains static objects and
it might be the case that each call to Component.getGraphicsConfiguration() returns the same object reference.
I was thinking that the safest approach would be to extract all relevant information from the GraphicsConfiguration on the EDT, pass it to the worker, and get a new BufferedImage() there with the suitable configuration. But I found some hints on the web that the result may lead to a surprising performance hit for drawImage(), suggesting that there might be config aspects which may not be covered explicitly.
Picking up haraldK's ideas, here is a thread-safe solution, which I have tested on a Linux PC with Java SE 1.6.0_26 and a Windows 8.1 notebook with Java SE 1.8.0_40. (Obviously, the code can be improved, buit that's beyond this Q&A.)
On both platforms, performance was comparable adjusted for processor speed, and also on both platforms, Transparency.BITMASK was handled via BufferedImage.TYPE_CUSTOM, while Transparency.OPAQUE and Transparency.TRANSLUCENT use specific corresponding BufferedImage.TYPE_* values.
Also on both platforms, there was no noticeable performance difference between using any of the two new BufferedImage() calls, while GraphicsConfiguration.createCompatibleImage() was definitely (30% to 50%) slower.
The whole mechanism is provided by an inner class. The outer class extends javax.swing.JComponent so there's no synchronisation at all at that level. However, the SwingWorkers are anonymous inner classes and deploy the image creation sync mechanism.
The distinction between the two categories of BufferedImage.getType() seems to be unnecessary on the tested platforms, but who knows.
In my case, the innter class also contains other information which the SwingWorkers need.
private static final class WokerSync
{
private Object refImageMutex = new Object();
private BufferedImage refImageOpaque = null;
private BufferedImage refImageTranspMask = null;
private BufferedImage refImageTranslucent = null;
public void setRefImagesFromEDT(final GraphicsConfiguration grConf) {
if (grConf != null) {
synchronized(this.refImageMutex) {
this.refImageOpaque = grConf.createCompatibleImage(1, 1, Transparency.OPAQUE);
this.refImageTranspMask = grConf.createCompatibleImage(1, 1, Transparency.BITMASK);
this.refImageTranslucent = grConf.createCompatibleImage(1, 1, Transparency.TRANSLUCENT);
}
}
}
private BufferedImage getCompatibleImage(final BufferedImage refImage, final int width, final int height) {
BufferedImage img = null;
if (refImage != null) {
final int grType = refImage.getType();
if (grType == BufferedImage.TYPE_CUSTOM) {
final ColorModel cm = refImage.getColorModel();
final WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
final String[] ps = refImage.getPropertyNames();
final int pl = (ps == null) ? 0 : ps.length;
final Hashtable<String,Object> ph = new Hashtable<String,Object>(pl);
for (int pi=0; pi<pl; pi++) {
ph.put(ps[pi], refImage.getProperty(ps[pi]));
}
img = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), ph);
} else {
img = new BufferedImage(width, height, grType);
}
}
return img;
}
public BufferedImage getCompatibleImageOpaque(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageOpaque, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranspMask(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranspMask, width, height);
}
return img;
}
public BufferedImage getCompatibleImageTranslucent(final int width, final int height) {
BufferedImage img = null;
synchronized(this.refImageMutex) {
img = this.getCompatibleImage(this.refImageTranslucent, width, height);
}
return img;
}
}

Is This correct way to use Soft References

I created a cache using Soft References a while ago, but in trying to resolve a bug I'm getting concerned that actually I've done it incorrectly and it's removing objects when it shouldn't. This is how I've done it:
private static final Map<String, SoftReference<Buffered>> imageMap =
new HashMap<String,SoftReference<Buffered>>();
public static synchronized Buffered addImage(String sum, final byte[] imageData)
{
SoftReference<Buffered> bufferedRef = imageMap.get(sum);
Buffered buffered;
if (bufferedRef!=null)
{
//There are no longer any hard refs but we need again so add back in
if(bufferedRef.get()==null)
{
buffered = new Buffered(imageData, sum);
imageMap.put(sum, new SoftReference(buffered));
}
else
{
buffered=bufferedRef.get();
}
}
else
{
buffered = new Buffered(imageData, logDescriptor, sum);
imageMap.put(sum, new SoftReference(buffered));
}
return buffered;
}
public static Buffered getImage(String sum)
{
SoftReference<Buffered> sr = imageMap.get(sum);
if(sr!=null)
{
return sr.get();
}
return null;
}
So the idea is a calling process can add new Buffered objects which can be identifed/looked up by the key sum, then as long as this Buffered object is being used by at least one object it won't be removed from the map, but if it is no longer being used by any objects then it could be garbage collection if memory gets tight.
But looking at my code now is the important thing that the key field sum is always being referenced somewhere else (which isn't necessarily the case)
EDIT: So I tried Colin's solution but I'm kind of stumped because putIfAbsent() doesn't seem to return the added value. I modified my addImage method to get some debugging
public static synchronized Buffered addImage(String sum, final byte[] imageData)
{
Buffered buffered = new Buffered(imageData, sum);
Buffered buffered2 = imageMap.get(sum );
Buffered buffered3 = imageMap.putIfAbsent(sum,buffered );
Buffered buffered4 = imageMap.get(sum );
System.out.println("Buffered AddImage1:"+buffered);
System.out.println("Buffered AddImage2:"+buffered2);
System.out.println("Buffered AddImage3:"+buffered3);
System.out.println("Buffered AddImage4:"+buffered4);
return buffered2;
}
returns
Buffered AddImage1:com.Buffered#6ef725a6
Buffered AddImage2:null
Buffered AddImage3:null
Buffered AddImage4:com.Buffered#6ef725a6
So it clearly show the Buffered instance wasn't there to start with and is successfully constructed and added, but surely should be returned by putIfAbsent?
I'd recommend using Guava's MapMaker instead of doing this yourself.
private static final ConcurrentMap<String, Buffered> imageMap =
new MapMaker().softValues().makeMap();
public static Buffered addImage(String sum, final byte[] imageData) {
Buffered buffered = new Buffered(imageData, sum);
Buffered inMap = imageMap.putIfAbsent(sum, buffered);
return inMap != null ? inMap : buffered;
}
public static Buffered getImage(String sum) {
return imageMap.get(sum);
}
Since this is a ConcurrentMap and uses putIfAbsent, you don't have to synchronize addImage unless creating an instance of Buffered is expensive. This also handles actually removing entries from the map when their value is garbage collected, unlike your code.
Edit: What do you do if you call getImage and get null as a result (perhaps because the value was garbage collected)? Is there some way that you can get the image data byte[] based on the sum key? If so, you may want to encapsulate the process of creating an instance of Buffered for a given sum as a Function<String, Buffered>. This allows you to use a computing map instead of a normal one:
private static final ConcurrentMap<String, Buffered> imageMap = new MapMaker()
.softValues()
.createComputingMap(getBufferedForSumFunction());
Done this way, you may not even need an addImage method... if get is called on the map and it doesn't have an entry for the given sum, it'll call the function, cache the result and return it.
If all you want to do is allow data to get garbage collected when it's not referenced anywhere, use a WeakHashMap.
If you want your map to actually be able to recreate the data if it is no longer available, then you'll need to modify the getImage() to check if the reference is available and if not, recreate it.
It seems to me that what you want is the former.
The difference between a soft reference and a weak reference is that the garbage collector uses algorithms to decide whether or not to reclaim a softly reachable object but always reclaims a weakly reachable object. (ref)

Categories

Resources