When I was creating my first tiled map creator in libGDX, I noticed a very strange bug. I creating grid of objects like this:
private static final int GRID_WIDTH=2400;
private static final int GRID_HEIGHT=2400;
private static final int CELL_SIZE=60;
so you can see there are 2400/60x2400/60 objects or cells. I am creating my map like this:
private void createMap(){
cells = new Cell[GRID_WIDTH/CELL_SIZE][GRID_HEIGHT/CELL_SIZE];
for(int i=0;i<GRID_WIDTH/CELL_SIZE;++i){
for(int j=0;j<GRID_HEIGHT/CELL_SIZE;++j){
cells[i][j]=new Cell(textures[0],i*CELL_SIZE,j*CELL_SIZE);
}
}
}
I also have coordinates for my debug in the screen so I know where they started to disappear. Y coordinate is ok there are from 0 to 2400, but on the X they started to disappear at 1500. When I start to draw there some texture every column will be visible to that texture for example (when I start to write texture at x=2100 every disappeared column will be visible to 2100) and when I will delete that texture every column will disappear again to 1500. So the objects are there but they are not visible. It is so annoying does anyone know about this bug?
As you can see coordinates are at the bottom left this is at the beginning:
and this is when I will add there some texture
[Edited] Code with camera:
private float x=GRID_WIDTH/2,y=GRID_HEIGHT/2;
#Override
public void render(float delta) {
batch = new SpriteBatch();
camera=new OrthographicCamera(CAM_WIDTH,CAM_HEIGHT);
viewPos = new Vector3();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
viewPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(viewPos);
batch.begin();
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT) || Gdx.input.isKeyPressed(Input.Keys.D))
x+=SPEED*Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Input.Keys.LEFT) || Gdx.input.isKeyPressed(Input.Keys.A))
x-=SPEED*Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Input.Keys.UP) || Gdx.input.isKeyPressed(Input.Keys.W))
y+=SPEED*Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Input.Keys.DOWN) || Gdx.input.isKeyPressed(Input.Keys.S))
y-=SPEED*Gdx.graphics.getDeltaTime();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
camera.position.set(x,y,0);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.end();
}
The camera is correct. The problem is the batch.begin() and batch.end(). As you might know you cannot do batch.begin() and then shaperenderer.begin() directly after each others without closing one of them. Reason for this I am not 100% about. stage works similar. This means we have to close the batch before drawing the stage
batch.end();
stage.draw();
batch.begin();
// draw your batch stuff here
Also it's terrible to do this
batch = new SpriteBatch();
camera=new OrthographicCamera(CAM_WIDTH,CAM_HEIGHT);
inside the render method. Instead, put it into the create() method or some of your own initialize method. The important thing is to not create a new SpriteBatch every frame as the batch isn't collected by the GC. So you have to manually dispose it using batch.dispose() or it will leak so much memory your RAM will be gone in no time.
I hope this helped you out, good luck.
Related
My ImageView is matching screen size on x-axis and is using remaining space on y-axis in my layout. I want to create bitmap into this ImageView with exactly the same size as the ImageView is. How to make it please? Can it be done by some automatic setting, should I call some measure function?
I tried SetAdjustViewBounds() but it didn't work for me.
Creating Bitmap big enough (I don't like much such a memory wasting) and setting SetScaleType(ImageView.ScaleType.Matrix) works, but still when I'm making drawing operations on canvas, I don't know real size of area I should paint into, both canvas and bitmap height are equal to yScreen while imgWeekView height is pretending to be 0, even though it paints whole desired area with gray color.
imgWeekView = new ImageView(context);
//imgWeekView.SetAdjustViewBounds(true);
imgWeekView.SetScaleType(ImageView.ScaleType.Matrix);
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent,1f);
layoutParams.Height = 0;
imgWeekView.LayoutParameters = layoutParams;
Bitmap bitmap = Bitmap.CreateBitmap((int)xScreen, (int)yScreen, Bitmap.Config.Argb8888);
cnvWeekView = new Canvas(bitmap);
imgWeekView.SetImageBitmap(bitmap);
linearLayout.AddView(imgWeekView); //whole activity layout
//Test
cnvWeekView.DrawColor(new Color(128, 128, 128));
Paint paint = new Paint(PaintFlags.AntiAlias);
paint.Color = new Color(255, 255,0);
cnvWeekView.DrawCircle(50, 50, 40, paint);
Finally I found a way how to measure my ImageView and here I will post my answer.
I believed that there should be much easier solution, but maybe there isn't. From this question I took most of the important data:
How to get the width and height of an android.widget.ImageView?
Things look however a little different in my android application and I'm not experienced enough to tell why. I had to change things a little. I had to learn a bit about interfaces and this question helped too.
Implementing the View.IOnTouchListener interface
Here is how I combined things. First I created class that will do the measure.
public class MyPredrawListener : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener
{
ImageView imageView;
public MyPredrawListener(ImageView img)
{
imageView = img;
}
public bool OnPreDraw()
{
imageView.ViewTreeObserver.RemoveOnPreDrawListener(this);
int finalHeight = imageView.MeasuredHeight;
int finalWidth = imageView.MeasuredWidth;
Bitmap bitmap = Bitmap.CreateBitmap(finalWidth, finalHeight, Bitmap.Config.Argb8888);
imageView.SetImageBitmap(bitmap);
//Test to see result
Canvas cnv = new Canvas(bitmap);
Paint paint = new Paint();
paint.Color = new Color(255, 255, 0);
cnv.DrawColor(new Color(128, 128, 128));
cnv.DrawCircle(finalWidth-50, finalHeight-50, 50, paint);
return true;
}
}
And in code where I create my imageView I set the listener like this.
imgWeekView = new ImageView(context);
MyPredrawListener listener=new MyPredrawListener(imgWeekView);
imgWeekView.ViewTreeObserver.AddOnPreDrawListener(listener);
In OnPreDraw function I put test code to see the result graphically, clearing bitmap to gray color and painting yellow circle to bottom right of a view.
this.canvas = new Canvas(shell, SWT.NO_BACKGROUND);
I'm using a PaintListener:
this.canvas.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
// Draw images
synchronized (imageMarks) {
for (ImageMark mark : Whiteboard.this.imageMarks)
{
Image image = Whiteboard.this.getImage(mark.id);
Point position = ScaledPoint.toSWTPoint(Whiteboard.this.getCanvasSize(), mark.getPosition());
Point bounds = mark.getUnscaledBoundaries(Whiteboard.this.getCanvasSize());
e.gc.drawImage(image, 0, 0, image.getBounds().width, image.getBounds().height, position.x, position.y,
bounds.x, bounds.y);
}
}
// Draw pencil marks
synchronized (pencilMarks) {
e.gc.setLineWidth(LINE_WIDTH);
for (double[] line : Whiteboard.this.pencilMarks)
{
Point lastPosPoint = ScaledPoint.toSWTPoint(Whiteboard.this.getCanvasSize(), new ScaledPoint(line[0], line[2]));
Point newPosPoint = ScaledPoint.toSWTPoint(Whiteboard.this.getCanvasSize(), new ScaledPoint(line[1], line[3]));
e.gc.drawLine(lastPosPoint.x, lastPosPoint.y, newPosPoint.x, newPosPoint.y);
}
}
// Draw pointer, assuming it's there
if (pointerMark != null)
{
synchronized (pointerMark) {
Point pos = ScaledPoint.toSWTPoint(Whiteboard.this.getCanvasSize(), pointerMark.getPosition());
if (pointerMark.isFlipped())
e.gc.drawImage(Whiteboard.pointerImageFlipped, pos.x, pos.y);
else
e.gc.drawImage(Whiteboard.pointerImage, pos.x, pos.y);
}
}
}
});
and redrawing the canvas via a canvas.redraw() call. On 64-bit Linux, this seems to be working without any issues, but strangely enough, on 64-bit Windows, nothing ever ends up being erased or redrawn. For example, if the screen is resized, the pencil markings do not resize as well, they just end up being cut out of the screen. When new marks are added (in other words, when the paint listener is called again), the repositioned markings are redrawn on top of the old ones which didn't scale with the window. In other words, I believe the canvas is not being cleared upon canvas.redraw(). Is there a workaround for this?
You are specifying SWT.NO_BACKGROUND which stops the Canvas being cleared before each paint.
If you use SWT.NO_BACKGROUND it is your paint method's responsibility to draw every pixel of the Canvas.
SWT.NO_BACKGROUND JavaDoc:
By default, before a widget paints, the client area is filled with the
current background. When this style is specified, the background is
not filled, and the application is responsible for filling every pixel
of the client area. This style might be used as an alternative to
"double-buffering" in order to reduce flicker. This style does not
mean "transparent" - widgets that are obscured will not draw through.
I have a JavaFX app which contains a line chart. I want users to be able to select the color of each series in the chart. Since the selection is dynamic I can't use static CSS to set the colors. I also have other controls that I need to set to the same color as the associated series. It's possible to set the line color of a series dynamically using code like this:
series.getNode().setStyle("-fx-stroke: " + color + ";");
That works well and I can use the user-specified color on the associated controls.
My problem is that I also need to set the color of the symbols for each series to the same color. I can't find any way to do that dynamically. All of the tutorials, documentation, and posts that I've read on the topic point to the static CSS approach.
Most charting widgets make this sort of thing very easy to do, but I've found no clues here or on the Oracle forums. Any guidance would be greatly appreciated.
-- Update --
I've found no way to do this other than to enumerate every data point in every series, grab the associated symbol node and set the style individually. Not what I was hoping for. In the process I realized that the default Node allocated for a symbol is a StackPane. I didn't need that flexibility so I replaced it with a Rectangle. This made rendering faster.
I'm late to the game, but maybe someone can use my solution. What worked for me, was iterating through every item in the data series and setting the CSS style for each one.
for (int index = 0; index < series.getData().size(); index++) {
XYChart.Data dataPoint = series.getData().get(index);
Node lineSymbol = dataPoint.getNode().lookup(".chart-line-symbol");
lineSymbol.setStyle("-fx-background-color: #00ff00, #000000; -fx-background-insets: 0, 2;\n" +
" -fx-background-radius: 3px;\n" +
" -fx-padding: 3px;");
}
I was stuck with a similar problem. I don't know upfront which data is going to be added to the graph, so I can't make use of a fixed stylesheet.
I came up with this solution. This code listens for new series added to graph. For every added series, it will create a new listener for data added to the series.
This listener will look up which series this is, the 0th, 1st, etc and then find the two nodes for the coloring of the line and of the legend/symbol.
As soon as it has set both, it can unsubscribe.
Problem can be that the legend/symbol node is not available yet when you receive the callback on the first added datapoint.
I'm aware it's very convoluted and I'm open to hear improvements.
At least it will give you the option to dynamically set the color to anything you want.
final LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(), new NumberAxis());
final ObservableList<Series<Number, Number>> series = chart.getData();
series.addListener(new ListChangeListener<Series<Number, Number>>() {
#Override
public void onChanged(Change<? extends Series<Number, Number>> change) {
ObservableList<? extends Series<Number, Number>> list = change.getList();
for (final Series<Number, Number> serie : list) {
serie.getData().addListener(new ListChangeListener<Data<Number, Number>>() {
#Override
public void onChanged(Change<? extends Data<Number, Number>> ignore) {
int index = series.indexOf(serie);
Set<Node> nodes = chart.lookupAll(".series" + index);
boolean isStyleSet = false;
for (Node n : nodes) {
if (StringUtils.isEmpty(n.getStyle())) {
String css = "-fx-stroke: %s; -fx-background-color: %s, white; ";
String color = //assign dynamically here, for instance based on the name of the series
n.setStyle(String.format(css, color, color));
isStyleSet = true;
}
}
if (!isStyleSet & nodes.size() > 1) {
serie.getData().removeListener(this);
}
}
});
}
}
});
I had a problem which might be slightly different (possibly more complex); I needed to style some nodes of a series one color, others within the same series another color (I also needed to be able to change the allocation of color dynamically). I am working in JavaFx 2.2; I have css-styling, but of course that does not help here. I could not find my issue addressed anywhere; this was the closest I've found.
I just want to say that I could not get "series.getNode().setStyle("-fx-stroke: " + color + ";")" to work. However, using "-fx-background" instead does work. I hope this helps someone.
I'm a little new to using MFC and VC++ as such, but I'm doing this as part of a Course and i Have to stick to VC++.
http://www.cprogramming.com/tutorial/game_programming/same_game_part1.html
This is the tutorial I have been following to make a simple samegame. However when i try to display score, the score is getting displayed Underneath or outside my application window, even though I've displayed score before calling updateWindow(). I've tried various methods but I am kinda lost here.
Here is the code I'm using to Display the score:
void CSameGameView::updateScore()
{
CSameGameDoc* pDoc = GetDocument();
CRect rcClient, rcWindow;
GetClientRect(&rcClient);
GetParentFrame()->GetWindowRect(&rcWindow);
int nHeightDiff = rcWindow.Height() - rcClient.Height();
rcScore.top=rcWindow.top + pDoc->GetHeight() * pDoc->GetRows() + nHeightDiff;
rcScore.left=rcWindow.left + 50;
rcScore.right=rcWindow.left + pDoc->GetWidth() - 50;
rcScore.bottom=rcScore.top + 20;
CString str;
double points = Score::getScore();
str.Format(_T("Score: %0.2f"), points);
HDC hDC=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
COLORREF clr = pDoc->GetBoardSpace(-1, -1); //this return background colour
pDC->FillSolidRect(&rcScore, clr);
DrawText(hDC, (LPCTSTR) str, -1, (LPRECT) &rcScore, DT_CENTER);
}
Thank you for any help and I'm sorry if the question doesn't make sense or in ambiguous.
There are several problems with your code:
1. The hDC you are creating is going to have coordinates relative to the desktop window. To paint text in your window, use CClientDC like this: CClientDC dc(this); (see http://msdn.microsoft.com/en-US/library/s8kx4w44%28v=vs.80%29.aspx)
2. The code you have will leak a DC every time the function is called. The method in #1 will fix that.
3. Your paint code should be done in the CView::OnDraw. There you get a DC passed to you and you don't have to worry about creating one with CClientDC. Set the variables you want to draw (e.g. your points or score), store them as class members and draw them in CView::OnDraw.
Don't do the drawing in your updateScore method.
Make sense? Hang in there!
To change brightness of an image in c#.net 4 i have used the following method.
public void SetBrightness(int brightness)
{
imageHandler.RestorePrevious();
if (brightness < -255) brightness = -255;
if (brightness > 255) brightness = 255;
ColorMatrix cMatrix = new ColorMatrix(CurrentColorMatrix.Array);
cMatrix.Matrix40 = cMatrix.Matrix41 = cMatrix.Matrix42 = brightness / 255.0F;
imageHandler.ProcessBitmap(cMatrix);
}
internal void ProcessBitmap(ColorMatrix colorMatrix)
{
Bitmap bmap = new Bitmap(_currentBitmap.Width, _currentBitmap.Height)
ImageAttributes imgAttributes = new ImageAttributes();
imgAttributes.SetColorMatrix(colorMatrix);
Graphics g = Graphics.FromImage(bmap);
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(_currentBitmap, new Rectangle(0, 0, _currentBitmap.Width,
_currentBitmap.Height), 0, 0, _currentBitmap.Width,
_currentBitmap.Height, GraphicsUnit.Pixel, imgAttributes);
_currentBitmap = (Bitmap)bmap.Clone();
}
If brightness is changed several times then "Out of memory" exception is shown. I have tried to use "Using block" but went in vein.
Any ideas?
please see the link
http://www.codeproject.com/Articles/227016/Image-Processing-using-Matrices-in-Csharp
and suggest if any types of optimization is possible in the methods (Rotation, brightness, crop and undo).
I have downloaded the projects from CodeProject and I have fixed the memory leak. You need to dispose the Graphics object and the _currentBitmap image before you override it. Also, you need to stop using .Clone.
If you replace the contents of the ProcessBitmap function with this code, the memory leak is gone:
internal void ProcessBitmap(ColorMatrix colorMatrix)
{
Bitmap bmap = new Bitmap(_currentBitmap.Width, _currentBitmap.Height);
ImageAttributes imgAttributes = new ImageAttributes();
imgAttributes.SetColorMatrix(colorMatrix);
using (Graphics g = Graphics.FromImage(bmap))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(_currentBitmap, new Rectangle(0, 0, _currentBitmap.Width, _currentBitmap.Height), 0, 0, _currentBitmap.Width, _currentBitmap.Height, GraphicsUnit.Pixel, imgAttributes);
}
_currentBitmap.Dispose();
_currentBitmap = bmap;
}
Also, here are some tips for further optimization:
Stop using .Clone(). I have seen the code, and it uses .Clone() everywhere. Don't clone objects unless really necessary. In image processing, you need a lot of memory to store large image files. You need to make as much processing as you can in-place.
You can pass Bitmap objects by reference between methods. You can improve performance and reduce the memory cost that way.
Always use using blocks when working with Graphics objects.
Call .Dispose() on the Bitmap objects when you're sure you don't need them anymore