Is Graphics2D.draw performed if the Shape is offscreen? - java

I'm currently working on some Rendering Code, and I wondered if Graphics2D.draw(Shape) is performed the exact same way onscreen as offscreen.
If it is, is there a way to check if my shape (a Line2D) is onscreen?

Depends on what you mean by "exactly the same way".
As far as calls to draw-something() from your code are concerned, they take place normally. What is different, somewhere in the rendering chain the condition that the shape does not actually fall into the actual rendering area is detected and no pixels are actually output for the shape.
As for detecting if something is "on screen", that depends what you define the screen as. Reasonably you would define it as the area described by your Graphics object (that may well be only part of the screen, or completely off screen, heck it could be a printer!).
Provided you have not changed the clip area of a Graphics instance, getClipBounds() gives you the rectangle where graphics are actually rendered. If your graphics comes from a Swing component, you can also substitute the components dimensions for the rendering area.
Once you have the actual Rectangle, you can make use of the methods provided by Shape to detect collisions (contains(), intersects() etc.).

Related

What does a Graphics object actually represents?

Ok, I'm not even sure if that is the right question to ask.
I've been confused by what is A Graphics object for a while now, I used to think that it is simplly a tool to use to change colors and draw to specific container(ie JFrame, JPanel).
However, I've been studying buffering(triple, double, flipping...etc) and how it works for 3 days now, and my confusion has only increased. for instance, why when we need to draw to the buffer(ie BufferStrategy, BufferedImage) we get its own graphics object to draw to it and then we project it to the screen? does the Graphics Object represent the drawing surface (ie the JPanel it self if we're using one to draw custom painting via JPanel#paintComponent(Graphics g)) ?
and so when we're getting the graphics object of a buffer, do we actually get its drawing surface to paint on?
Please somebody explain, any help is appreciated
Thanks
From the API:
A Graphics object encapsulates state information needed for the basic
rendering operations that Java supports. This state information
includes the following properties:
The Component object on which to draw.
A translation origin for rendering and clipping coordinates.
The current clip.
The current color.
The current font.
The current logical pixel operation function (XOR or Paint).
The current XOR alternation color (see setXORMode(java.awt.Color)).
So a Graphics instance contains information about WHERE to draw (a component) as well as HOW to draw it (a color, font, etc). It then gives you methods so you can tell it WHAT to draw (a rectangle, circle, text, etc).

(OpenGL) Clamping large content to smaller area

I'm using OpenGL wigh LWJGL in Java, but that's not important here. I'm not asking for code, but for a hint on how to do this. Language independent.
I have some region (a rectangle for simplicity), and, let's say, a big tiled map which I want to show in this area. The area is not the whole screen, I want to render something around it.
I know about a few approaches, but all are either huge pain or unsuitable.
Render the whole tiled map and everything else, including background and the frame,
on top - leaving the window. Yes, works, but it'd be pain.
Render only visible tiles and only the visible portions of the border tiles.
Again, doable but hard, and ie. when I use external font drawing library, I can't just tell it "Hey, stop at this line, there's my border." Not very good approach, I'd say.
Some OpenGL magic which I'm not aware of.
Guide me.
When your area is guaranteed to be an axis-aligned rectangle, you can just use glViewport and/or glScissor (the latter together with glEnable(GL_SCISSOR_TEST)) to prevent OpenGL from rendering outside that rectangle.
In case of modifying the viewport, the image resulting just is scaled to fit the viewport rectangle. Using the scissor test, the area is just "cut out", so not scaled with respect to the viewport setting. But the differences do not really even matter -you can get to the same result via both paths by just adjusting your transformations accordingly. Just note that, if you need to call glClear when you render your "tiled map", the clear operation will not be limited by the currently set viewport, but the scissor test will allow you to even limit the clearing.
If you're area can not be described as an axis-aligned rectangle, I'll recommend having a look at the stencil buffer. The algorithm is simple:
Clear stencil buffer to 0.
Just render the shape you want your tiled map to appear _only into the stencil buffer.
When rendering your tiled map, enable stencil test and set it up so that it will discard fragments for pixels the stencil buffer is 0.
Steps 1 and 2 do only have to be done once (as long as your area is not changing, or your windo size). Have a look at the glStencilFunc and glStencilOp functions for details of how to do that.

Suggestion for implementing a drawing program - UML designer

This program will have an infinite canvas (ie as long as the user scrolls, it becomes bigger) with a tiled background image, and you can drag and drop blocks and draw arrows between blocks. Obviously I won't use a layout manager for placing blocks and lines, since they will be absolutely positioned (any link on this, possibily with a snapping feature?). The problem arises with blocks and lines. Basically I'll have two options:
Using a simple layout for each building block. This is the simplest and clearest approach, but does it scale well when you have hundreds of objects? This may not be uncommon, just imagine a database with 50 tables and dozens of relationships
Drawing everything with primitives (rectangles, bitmaps, etc). This seems too complicated (especially things like text padding and alignment) but may be more scalable if you have a large number of objects. Also there won't be any event handler
Please give me some hints based on your experience. I have never drawn with Java before - well I did something rather basic with PHP and on Android. Here is a simple preview
DISCLAIMER
You are not forced to answer this. I am looking for someone who did something like this before, what's the use of writing I can check an open source project? Do you know how difficult it is to understand someone else's code? I'm talking about implementations details here... Moreover, there is no guarantee that he's right. This project is just for study and will be funny, I don't want to sell it or anything and I don't need your authorization to start it.
Measuring and drawing text isn't such a pain, since java has built in classes for doing that. you may want to take a look at the 2D Text Tutorial for more information. In fact, I did some text drawing computations with a different graphics engine which is much more primitive, and in the end it was rather easy (at least for the single-line drawing, for going multiline see the previous link).
For the infinite canvas problem, that's also something I always wanted to be able to do. A quick search here at stackoverflow gives this which sounds nice, althought I'm not sure I like it. What you can do, is use the way GIMP has a scroll area that can extend as you move - catch the click of the middle mouse button for marking the initial intention to move the viewport. Then, when the mouse is dragged (while the button is clicked) move the viewport of the jscrollpane by the offset between the initial click and the current position. If we moved outside the bounds of the canvas, then you should simply enlarge the canvas.
In case you are still afraid of some of the manual drawing, you can actually have a JPanel as your canvas, with a fixed layout. Then you can override it's paint method for drawing the connectors, while having child components (such as buttongs and text areas) for other interaction (and each component may override it's own paint method in case it wants to have a custom-painted rect).
In my last drawing test in java, I made an application for drawing bezier curves (which are basically curves made of several control points). It was a JPanel with overidden paint method that drew the curve itself, and buttons with custom painting placed on the location of the control points. Clicking on the control point actually was clicking on a button, so it was easy to detect the matching control point (since each button had one control point associated with it). This is bad in terms of efficiency (manual hit detection may be faster) but it was easy in terms of programming.
Anyway, This idea can be extended by having one child JPanel for each class rectangle - this will provide easy click detection and custom painting, while the parent will draw the connectors.
So in short - go for nested JPanels with custom drawing, so that you can also place "on-canvas" widgets (and use real swing widgets such as text labels to do some ready drawing) while also having custom drawing (by overriding the paint method of the panels). Note that the con of this method is that some swing look-and-feel's may interfere with your drawing, so may need to mess a bit with that (as far as I remember, the metal and nimbus look-and-feel's were ok, and they are both cross-platform).

Painting Program

I'm writing a simple painting program. To simulate a pencil drawing, I've stored the drawn points in a set, so when the window is resized the points won't be gone, and whenever another point is added I call the repaint method (the paint method draws all paints in the array on screen). But when the number of points increases, the program runs slowly.
Is there a more efficient method to do this?
The fastest way to get constant-speed repainting is to store the entire image that's drawn as a bitmap, and of course update it when the user draws. This way, you can redraw the right thing, and even add scrollbars and the like if you want. You can keep the array of points for an "undo" feature, for example.
If instead you want to make a vector-drawing program, then you have to keep the individual primitive operations (such as line, rectangles, etc). In that case it still pays off to keep an image for fast repainting, and now the trick becomes how to efficiently update that image when the user modifies the drawing (e.g. by resizing a rectangle). One way to do that is to tile the drawing area into lots of smaller ones, so you only need to recompute the underlying image for the parts that intersect with the object being modified by the user.
In both techniques, you'd use double-buffering just so that the user doesn't perceive flicker. But with double-buffering alone, the "redraw the whole set of points" would still be slow.
Since you haven't give any code, I am guessing that you are using primitive drawing methods (like draw a line or point).
A good option would be to use the Double Buffering technique to do the painting.
Look up GeneralPath.
What you can do is create a Shape class, that'll vary according to what you are going to draw (Rectangle, Triangle, Point, Line, etc.). You should do this even though now you're only drawing points.
When you create your Shape have code that checks what Shape to create, something like a switch/case statement:
...
case PENCIL:
if (generalPath == null) {
generalPath = new GeneralPath();
generalPath.moveTo(p1.x, p1.y);
} else {
generalPath.lineTo(p2.x, p2.y);
}
shape = generalPath;
break;
...
In the code that draws, simply call repaint and the Shape will be drawn.

Floating Rectangle on Screen

I know how to draw a rectangle onto a JPanel, but how can I paint a rectangle to the screen so that the rectangle appears to be floating? More specifically, a non-filled rectangle. My thought is to use a transparent JFrame with a rectangle drawn on it; however, this makes all of the content in the JFrame transparent.
My Solution
So I think there are many ways of going about this, some more complex than others, some more practical than others.
I tried the splash screen. The problem with that is you need to pass VM parameters "-splash " when you run. I created a manifest file to automate this/put the parameters into eclipse; but then the code is dependent on the .gif file and I can't change the size/position of the rectangle easily. Similar problems occur while faking it via screen screenshot. Good suggestions though, I learned some pretty cool stuff.
So, back to what I did. I used a JFrame, got the content pane and set the background to red (what ever color you want), then set the frame undecorated which removes the titlebar and border of the window. This created a floating rectangle which I could easily change the size and location of (frame.setSize, .setLocation). I have yet to make this a non filled rectangle, I tried internal frames and layeredpanes, but no success.
JFrame is a heavyweight component, and those were always opaque for the longest time. However, since Java 6u10, there is an inofficial API for transparent windows in the class com.sun.awt.AWTUtilities, which will most likely become official in Java 7. In earlier versions, the only way to simulate this kind of thing was to fake it via screenshots taken with java.awt.Robot
You would probably have to have parts of the window transparent while the actual drawn rectangle is not. I doubt there is a platform-agnostic solution for this so you would need to resort to JNI for this. Depending on what you need to do it might also be nice to make the window invisible for clicks which would need other tricks as well.
https://github.com/twall/jna/
That project offers a library and has examples of a clock and info balloons that are semi-transparent and transcend even what you're trying to do. The demos work well on Windows but I couldn't speak to how cross platform they are.
You might want to look at JLayeredPane. The demo on this page shows partially what you want, however when painting your rectangle you'll need to set your paint to transparent:
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
g2d.setComposite(ac);
g2d.drawImage(image, x, y, this);

Categories

Resources