XNA 4.0 Spritbatch - render target must not be set on the device - xna-4.0

i am converting a XNA 3.0 cloud effect into XNA 4.0 but i get an error
"The render target must not be set on the device when it is used as a texture."
It happens in the second loop in this line:
mover.Parameters["PressureMap"].SetValue(PressureOffsets);
Code:
for (int i = 0; i < 10; i++)
{
graf.SetRenderTarget(rt5);
mover.Parameters["PressureMap"].SetValue(PressureOffsets);
mover.Parameters["DivergenceMap"].SetValue(Divergence);
mover.CurrentTechnique = mover.Techniques["Jacobi"];
mover.CurrentTechnique.Passes[0].Apply();
sp.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointWrap, DepthStencilState.DepthRead, RasterizerState.CullNone);
sp.Draw(Velocity, new Vector2(0, 0), Color.White);
sp.End();
graf.SetRenderTarget(null);
PressureOffsets = rt5;
}
It seems I cant set in XNA 4.0 an texture as an effect parameter, if its already set as rendertarget.
But I dont know how to convert this to work in XNA 4.0 :(

I solved it.
Its necessary to change the rendertarget with a new one.
I used a helper Class "RenderTargetState".
public RenderTargetState SetToDevice()
{
oldState = new RenderTargetState(GraphicsDevice);
GraphicsDevice.SetRenderTarget(new RenderTarget2D(GraphicsDevice, renderTargetWidth, renderTargetHeight));
return oldState;
}
public RenderTargetState BeginRenderToTexture()
{
oldState = SetToDevice();
return oldState;
}
public Texture2D EndRenderGetTexture()
{
RenderTargetState renderBuffer = oldState.SetToDevice();
oldState = null;
return renderBuffer.RenderTarget;
}
So the code looks like this now:
for (int i = 0; i < 10; i++)
{
rt5.BeginRenderToTexture();
graf.SetRenderTarget(rt5.RenderTarget);
mover.Parameters["PressureMap"].SetValue(PressureOffsets);
mover.Parameters["DivergenceMap"].SetValue(Divergence);
mover.CurrentTechnique = mover.Techniques["Jacobi"];
mover.CurrentTechnique.Passes[0].Apply();
sp.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
sp.Draw(Velocity, new Vector2(0, 0), Color.White);
sp.End();
graf.SetRenderTarget(null);
PressureOffsets = rt5.EndRenderGetTexture();
}

There's an easier way to do this.
rt5 = PressureOffsets as RenderTarget2D
graf.SetRenderTarget(null);
PressureOffsets = rt5;

Related

Xamarin.Forms ZXing BarcodeReaderGeneric returns null when scanning an image in the gallery

I am developing a barcode reader with Xamarin.Forms. And I'm trying to scan the image on Android device.
First I select the image from the gallery with Xamarin.Essentials MediaPicker and from the path of this image I get an RGBLuminance with the Dependency class.
Then I am trying to decode this RGBLuminance with the Decode() method of the ZXing BarcodeReaderGeneric class. However, the result always returns null.
It is my demo project : https://onedrive.live.com/?authkey=%21AFLjjM91wgZkBGU&cid=58BE2C2C3447FFA2&id=58BE2C2C3447FFA2%219829&parId=root&action=locate
Command in the ViewModel class:
public ICommand PickCommand => new Command(PickImage);
private async void PickImage()
{
var pickResult = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
{
Title = "Select a barcode."
});
var path = pickResult.FullPath;
var RGBLuminance = DependencyService.Get<ILuminance>().GetRGBLuminanceSource(path);
var reader = new BarcodeReaderGeneric();
var result = reader.Decode(RGBLuminance); // result always null.
}
Method of Dependency class in Android:
public RGBLuminanceSource GetRGBLuminanceSource(string imagePath)
{
if (File.Exists(imagePath))
{
Android.Graphics.Bitmap bitmap = BitmapFactory.DecodeFile(imagePath);
List<byte> rgbBytesList = new List<byte>();
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
var c = new Android.Graphics.Color(bitmap.GetPixel(x, y));
rgbBytesList.AddRange(new[] { c.A, c.R, c.G, c.B });
}
}
byte[] rgbBytes = rgbBytesList.ToArray();
return new RGBLuminanceSource(rgbBytes, bitmap.Height, bitmap.Width, RGBLuminanceSource.BitmapFormat.RGB32);
}
return null;
}
You should change the line
return new RGBLuminanceSource(rgbBytes, bitmap.Height, bitmap.Width, RGBLuminanceSource.BitmapFormat.RGB32);
to
return new RGBLuminanceSource(rgbBytes, bitmap.Width, bitmap.Height, RGBLuminanceSource.BitmapFormat.RGB32);
And to be more accurate with the RGB format you should
change RGBLuminanceSource.BitmapFormat.RGB32 to RGBLuminanceSource.BitmapFormat.ARGB32
or change rgbBytesList.AddRange(new[] { c.A, c.R, c.G, c.B }); to rgbBytesList.AddRange(new[] { c.R, c.G, c.B, c.A });
Can you try with this pictures?
Picture One
Picture Two

How to remove a selected part of an image in Flutter?

I want to send an image to backend, but before sending user can select some part of it. And I need to remove unwanted part. Below I attached some screenshots.
After three days of working on it I finally found out, how to work around.
So if it's not an eraser I'm just drawing as always but if an eraser I'm replacing Paint with shader wich is my image from background.
if (!_eraser) {
paint = new Paint()
..style = PaintingStyle.fill
..strokeCap = StrokeCap.round
..color = selectedColor
..strokeWidth = strokeWidth;
} else {
final Float64List deviceTransform = new Float64List(16)
..[0] = devicePixelRatio
..[5] = devicePixelRatio
..[10] = 1.0
..[15] = 2.0;
paint = new Paint()
..style = PaintingStyle.fill
..strokeCap = StrokeCap.round
..shader = ImageShader(image, TileMode.repeated, TileMode.repeated, deviceTransform)
..strokeWidth = strokeWidth;
Painting Class
#override
void paint(Canvas canvas, Size size) {
canvas.drawImage(image, Offset.zero, new Paint());
for (int i = 0; i < pointsList.length - 1; i++) {
if (pointsList[i] != null && pointsList[i + 1] != null) {
canvas.drawLine(pointsList[i].points, pointsList[i + 1].points, pointsList[i].paint);
} else if (pointsList[i] != null && pointsList[i + 1] == null) {
offsetPoints.clear();
offsetPoints.add(pointsList[i].points);
offsetPoints.add(Offset(pointsList[i].points.dx + 0.1, pointsList[i].points.dy + 0.1));
canvas.drawCircle(pointsList[i].points, pointsList[i].paint.strokeWidth / 2, pointsList[i].paint);
}
}
}
If you want to crop the image basic on some user input that you already have, you could use the copyCrop function from the image library.

How to render Sprites normally on rotated isometric tiles? LIBGDX

i was using this tutorial to make an isometric Map from normal Sprites:
http://www.badlogicgames.com/wordpress/?p=2032
I want to render a house on top of my floor tiles at position 0,0, but it looks like this:
http://gyazo.com/c7d5cd74829150c684cfa7b40c9fdfba
Here is my create() and render():
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture(Gdx.files.internal("grass2d.jpg"));
//House
house = new Sprite(new Texture(Gdx.files.internal("mb_0004.png")));
house.setSize(2,2);
house.setPosition(0,0);
// Camera
cam = new OrthographicCamera(10,10*(Gdx.graphics.getHeight()/(float)Gdx.graphics.getWidth()));
cam.position.set(5,5,10);
cam.direction.set(-1,-1,-1);
cam.near = 1;
cam.far = 100;
//Matrices
//Matrix to rotate floor tiles
matrix.setToRotation(new Vector3(1,0,0), 90);
// Subject to change?
matrix2.setToRotation(new Vector3(0,1,0),45);
// populate Tiles
for(int z = 0; z < 100; z++) {
for(int x = 0; x < 100; x++) {
sprites[x][z] = new Sprite(img);
sprites[x][z].setPosition(x,z);
sprites[x][z].setSize(1, 1);
}
}
Gdx.input.setInputProcessor(this);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.setTransformMatrix(matrix);
batch.begin();
for(int z = 0; z < 100; z++) {
for(int x = 0; x < 100; x++) {
sprites[x][z].draw(batch);
}
}
batch.end();
batch.begin();
//batch.setTransformMatrix(matrix2);
house.draw(batch);
batch.end();
I did try to create another Matrix to transform it back, but then my coordinates are messed up. Hope you guys can help.
i was able to do it using TiledMap and a self written algorithm to detect wether or not a tile has been clicked and which one. I am able to place my house by mouse now and really like the result.
If anybody is interested, i will take some time to write a small tutorial.
Here is what it looks like at the moment:
Isometric Tiles

WriteableBitmap not invalidating and rendering in Windows Phone but working in silverlight5?

I am having a property which returns WriteableBitmap. when i am binding that property to the silverlight5 Image it showing the image, but when i am doing that in the WP it is not showing the image. when i am googling around this issue i saw that in WP the raw pixel values did not have alpha bits is set. But the same is working with silverlight. I don't know what is happening. Anybody have the similar issue or any round about?
(Imageproperty as WriteableBitmap).Invalidate();
<Image Source="{Binding Imageproperty}"/> (this is working in silverlight not in WP(7.1))
I had a similar sort of issue when trying to port some of the FaceLight code across from Silverlight to Windows Phone. The easiest way around this would be to manually set the Alpha value to 255 / opaque. So say if you had your WriteableBitmap that you wanted to display, result:
//convert to byte array
int stride = result.PixelWidth * 4; //brga32 is 32
int bytes = Math.Abs(stride) * result.PixelHeight;
byte[] data = result.ToByteArray();
int dataIndex = 0;
int nOffset = stride - result.PixelWidth * 4;
for (int y = 0; y < result.PixelHeight; ++y)
{
for (int x = 0; x < result.PixelWidth; ++x)
{
data[dataIndex + 3] = 0xFF; //set alpha to 255
dataIndex += 4; //skip to next pixel
}
dataIndex += nOffset;
}
WriteableBitmap finalImg = new WriteableBitmap(input.PixelWidth, input.PixelHeight);
return finalImg.FromByteArray(data);
Displaying the result from this method (the finalImg.FromByteArray(data) call) should display properly on the phone.
An alternative to this method above as well, is writing the WriteableBitmap to a .jpeg and then display the .jpeg instead - that seemed to work for me also but I didn't investigate that too thoroughly.
If the writeablebitmap has its pixeldata set or changed after the binding is established you need to call Invalidate to cause an update of the screen.
This goes for both Silverlight and Phone but you might have a race condition here that runs differently on both platforms.
I know it's an old post, but today I encountered the same problem on Windows Phone 8.1 Silverlight and I found nice solution, so I have decided to left it for people with similar problem. It was posted by Charles Petzold on MSDN as Video Feeds on Windows Phone 7 (it is shown on VideoSink class example, but it shouldn't be a problem to reproduce it with other case). He created a simple class that derives from VideoSink:
SimpleVideoSink C# code:
public class SimpleVideoSink : VideoSink
{
VideoFormat videoFormat;
WriteableBitmap writeableBitmap;
Action<WriteableBitmap> action;
public SimpleVideoSink(Action<WriteableBitmap> action)
{
this.action = action;
}
protected override void OnCaptureStarted() { }
protected override void OnCaptureStopped() { }
protected override void OnFormatChange(VideoFormat videoFormat)
{
this.videoFormat = videoFormat;
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
writeableBitmap = new WriteableBitmap(videoFormat.PixelWidth,
videoFormat.PixelHeight);
action(writeableBitmap);
});
}
protected override void OnSample(long sampleTimeInHundredNanoseconds,
long frameDurationInHundredNanoseconds, byte[] sampleData)
{
if (writeableBitmap == null)
return;
int baseIndex = 0;
for (int row = 0; row < writeableBitmap.PixelHeight; row++)
{
for (int col = 0; col < writeableBitmap.PixelWidth; col++)
{
int pixel = 0;
if (videoFormat.PixelFormat == PixelFormatType.Format8bppGrayscale)
{
byte grayShade = sampleData[baseIndex + col];
pixel = (int)grayShade | (grayShade << 8) |
(grayShade << 16) | (0xFF << 24);
}
else
{
int index = baseIndex + 4 * col;
pixel = (int)sampleData[index + 0] | (sampleData[index + 1] << 8) |
(sampleData[index + 2] << 16) | (sampleData[index + 3] << 24);
}
writeableBitmap.Pixels[row * writeableBitmap.PixelWidth + col] = pixel;
}
baseIndex += videoFormat.Stride;
}
writeableBitmap.Dispatcher.BeginInvoke(() =>
{
writeableBitmap.Invalidate();
});
}
}
However, this code needs some modification - VideoSink.CaptureSource must be provided with our CaptureSource (I just passed it into constructor):
public SimpleVideoSink(CaptureSource captureSource, Action<WriteableBitmap> action)
{
base.CaptureSource = captureSource;
this.action = action;
}
When we initialize SimpleVideoSink class in a ViewModel, we have to provide it an Action parameter. In my case it was enough to provide ViewModel with initialized field writeableBitmap:
ViewModel C# code:
private WriteableBitmap videoWriteableBitmap;
public WriteableBitmap VideoWriteableBitmap
{
get
{
return videoWriteableBitmap;
}
set
{
videoWriteableBitmap = value;
RaisePropertyChanged("VideoWriteableBitmap");
}
}
private void OnWriteableBitmapChange(WriteableBitmap writeableBitmap)
{
VideoWriteableBitmap = writeableBitmap;
}
//this part goes to constructor/method
SimpleVideoSink videoFrameHandler = new SimpleVideoSink(captureSource, OnWriteableBitmapChange);
Then all we have to do is to bind it to View:
View XAML code:
<Image Source="{Binding VideoWriteableBitmap}" />
In this example Image source is refreshed on every OnSample method invocation, and is dispatched to main thread through WriteableBitmap.Dispatcher.
This solution generates proper image with no blank pixel (alpha channel is also filled), and Invalidate() method works as it should.

Add a child inside a newly created instance, inside of a loop in AS3

I am trying to create a gallery where each thumb is housed inside of it's own movie clip that will have more data, but it keeps failing because it won't let me refer to the newly created instance of the movie clip. Below is what I am trying to do.
var xml:XML;
var xmlReq:URLRequest = new URLRequest("xml.xml");
var xmlLoader:URLLoader = new URLLoader();
var imageLoader:Loader;
var vidThumbn:ThumbNail;
var next_y:Number = 0;
for(var i:int = 0; i < xml.downloads.videos.video.length(); i++)
{
vidThumbn = new ThumbNail();
imageLoader = new Loader();
imageLoader.load(new URLRequest(xml.downloads.videos.video[i].ThumbnailImage));
vidThumbn.y = next_y;
vidThumbn.x = 0;
next_y += 117;
imageLoader.name = xml.downloads.videos.video[i].Files[0].File.URL;
videoBox.thumbList.thumbListHolder.addChild(vidThumbn);
videoBox.thumbList.thumbListHolder.vidThumbn.addChild(imageLoader);
}
It dies every time on that last line. How do I refer to that vidThumbn instance so I can add the imageLoader? I don't know what I'm missing. It feels like it should work.
You have to refer to it as vidThumbn, not the extended address....
i think it fails because the imageLoader hasn't loaded the image. Furthermore imageLoader doesnt hold the "data" its iamgeLoader.content
best way:
create a "LoaderSprite class" instead of imageLoader = new Loader();
public class LoaderSprite extends Sprite
{
private var _ldr : Loader;
public function LoaderSprite(url : String)
{
_ldr = new Loader();
_ldr.load(new URLRequest(url));
_ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
}
private function onComplete(event : Event) : void
{
//Bitmap(_ldr.content).smoothing = true;
addChild(_ldr.content);
// Fireing your own event
//dispatchEvent(new LoaderSpriteEvent(LoaderSpriteEvent.LOADED));
}
}

Resources