Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Offline fool  
#1 Posted : Tuesday, May 1, 2012 2:19:21 PM(UTC)
fool

Joined: 8/24/2011(UTC)
Posts: 34
Location: New Zealand

Thanks: 4 times
I've decided to wait no more and have created a Delta Engine project and I'm in the process of wiring up various services. Looks promising so far! ;)

The first problem I've hit is I need to update a texture every frame. I've had a look around the code and my thoughts were

1) Texture.Create, Texture.ctor (and hence any derived Texture.ctor) need an overload that does not require the setByteData parameter, i.e. this overload should only create the texture with all the other appropriate parameters.

which leads to

2) FillTextureData should be split into two methods as it's both creating the actual texture and then setting the texture data.

then this SetTextureData method, or whatever you'd call it, should be publicly accessible.

I can't see any problems with the various implementations like OpenTK, Xna, SharpDX, etc - unless I'm missing something? Speaking of which, I only seem to have the OpenTK implementation of Delta.Graphics. How do I get the others?

If the Delta Engine developers - or is that now just Benjamin - could do this I'd be grateful. Any chance? ;)

Wanna join the discussion?! Login to your forum accountregister a new account. Or Connect via Facebook Twitter Google

Offline Benjamin  
#2 Posted : Tuesday, May 1, 2012 6:18:18 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Hi there.

I am not sure what you mean by "update a texture every frame" and "FillTextureData should be split into two methods as it's both creating the actual texture and then setting the texture data.". Why would this be useful for you?

If I understand you correctly you just want to upload new data to an existing texture handle. Since the source code is all there you can fix this by just changing a single line of code (I admit we did not test this much and this is obviously wrong, I have already fixed it for the next release):

From OpenTKTexture.cs:
Code:

			// Create the texture in OpenGL and use the textureHandle from now on.
			GL.GenTextures(1, out textureHandle);


Is now changed to:
Code:

			// Create the texture in OpenGL and use the textureHandle from now on.
			// Note: If the texture was already created before and not disposed, just
			// use the existing handle, this allows overwriting the texture data.
			if (textureHandle == MathHelper.InvalidIndex)
			{
				GL.GenTextures(1, out textureHandle);
			}


And here is a little new unit test to show how to update texture data (runs with about 3000fps in my android simulator under windows I am currently testing out, probably more with OpenTK):
Code:

		#region UpdateTextureDynamically
		/// <summary>
		/// Simple test that shows how to update rgb texture data dynamically.
		/// </summary>
		[Test]
		public static void UpdateTextureDynamically()
		{
			// Define a 8x8 texture with some colors.
			Color[] textureColors = new[]
			{
				Color.Red, Color.Green, Color.Yellow, Color.Blue,
				Color.Black, Color.White, Color.Brown, Color.Orange,
				Color.Green, Color.Yellow, Color.Blue, Color.Black,
				Color.White, Color.Brown, Color.Orange, Color.Red,
				Color.Yellow, Color.Blue, Color.Black, Color.White,
				Color.Brown, Color.Orange, Color.Red, Color.Green,
				Color.Blue, Color.Black, Color.White, Color.Brown,
				Color.Orange, Color.Red, Color.Green, Color.Yellow,
				Color.Black, Color.White, Color.Brown, Color.Orange,
				Color.Red, Color.Green, Color.Yellow, Color.Blue,
				Color.White, Color.Brown, Color.Orange, Color.Red,
				Color.Green, Color.Yellow, Color.Blue, Color.Black,
				Color.Brown, Color.Orange, Color.Red, Color.Green,
				Color.Yellow, Color.Blue, Color.Black, Color.White,
				Color.Orange, Color.Red, Color.Green, Color.Yellow,
				Color.Blue, Color.Black, Color.White, Color.Brown,
			};
			// Convert the colors to rgb data and create texture out of it plus
			// pass it into a material for rendering.
			Texture dynamicTexture = Texture.Create(
				Texture.ConvertColorToRgb(textureColors), new Size(8, 8),
				BlendMode.Opaque, false);
			Material2D dynamicMaterial = new Material2D(dynamicTexture);

			// Add an offset to the textureColors array to keep changing texture data
			int textureColorOffset = 0;
			Color[] rotatedTextureColors = new Color[textureColors.Length];

			Application.Start(delegate
			{
				// Update the texture with new data each tick
				for (int num = 0; num < rotatedTextureColors.Length; num++)
				{
					rotatedTextureColors[num] =
						textureColors[(num + textureColorOffset) % textureColors.Length];
				}
				textureColorOffset++;
				dynamicTexture.UpdateTextureData(
					Texture.ConvertColorToRgb(rotatedTextureColors));

				// And show the material with the dynamic texture normally
				dynamicMaterial.Draw(new Rectangle(0.2f, 0.2f, 0.6f, 0.6f));
			});
		}
		#endregion


It uses the new helper method UpdateTextureData in Texture.cs, which just uses the FillTextureData method like before, but adds some checks:
Code:

		#region UpdateTextureData
		/// <summary>
		/// Update the texture data with a given RGB or RGBA byte array. Unlike
		/// Create and FillTextureData this method is called after the texture has
		/// been created and should only be used to update it without changing the
		/// width, height or texture format.
		/// </summary>
		public void UpdateTextureData(byte[] newImageData)
		{
			// Currently only uncompressed rgb or rgba textures can be updated.
			if (extensionUsed !=
				(HasAlpha
					? "rgba"
					: "rgb"))
			{
				throw new NotSupportedException(
					"Sorry, the extension '" + extensionUsed + "' for the loaded " +
					"texture '" + Name + "' currently is not supported in this method " +
					"to update the texture data. Please create or load the texture " +
					"from rgb or rgba data!");
			}

			// Make sure the texture size fits the data.
			int numberOfPixels =
				newImageData.Length /
				(HasAlpha
				 	? 4
				 	: 3);
			int expectedPixels = (int)Size.Width * (int)Size.Height;
			if (expectedPixels != numberOfPixels)
			{
				throw new ArgumentException(
					"Sorry, unable to update texture data. Only '" + numberOfPixels +
					"' pixels were submitted, but the texture size is '" + Size +
					"', expecting '" + expectedPixels + "' pixels!");
			}

			// And finally update the texture data like for the first upload.
			FillTextureData((int)Size.Width, (int)Size.Height, newImageData,
				extensionUsed);
		}
		#endregion


If I missed something please be more clear on what you want to accomplish or maybe try to fix it yourself. The graphics source code is all there, all of the changes I made above can be made by anyone else too. Patching something is quick and easy for me and saves time. Thanks for the suggestion though, hopefully the fix is useful for you.
thanks 1 user thanked Benjamin for this useful post.
fool on 5/1/2012(UTC)
Offline fool  
#3 Posted : Tuesday, May 1, 2012 10:02:46 PM(UTC)
fool

Joined: 8/24/2011(UTC)
Posts: 34
Location: New Zealand

Thanks: 4 times
Hi Benjamin

That's pretty damn close to what I was thinking, thanks! The only difference being I'd need to have the data around at Create time, which I don't until the first frame (since it's generated), but the way you've done it has the least impact on the existing code and is the same as starting out 'clear'. I'll have a play with it when I get home tonight.

One quick question, what's the story with the RGBA byte ordering across all the different platforms? Specifically, can I assume a particular byte order so that I can generate the RGBA in place in my own byte[]? That way I can avoid the need to use a Color[] and then ConvertColorToRgb (which generates garbage) to get the byte[]. Texture.ConvertColorToRgb doesn't seem to do any platform checks, so the byte order looks to be always red, then green, etc.
Offline Benjamin  
#4 Posted : Tuesday, May 1, 2012 10:35:17 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Well, you can just fill the newly created texture with all 0 (black transparent), just pass in an empty byte array:
Code:

			Texture dynamicTexture = Texture.Create(
				new byte[8*8*3], new Size(8, 8), BlendMode.Opaque, false);


Byte ordering is also not a problem because .NET code behaves the same on all platforms (always little-endian, if you are interested). I don't think there is even any code in the Delta Engine caring about this ^^

GPUs do not care about byte ordering either, texture formats must always fit the exact specification, there is no byte reordering done. There are some differences with ARGB, RGBA, BGRA formats (you can check it out yourself in OpenTKTexture.cs), but you don't need to worry about this because the engine will always try to find the most optimal format for you.

Originally Posted by: fool Go to Quoted Post
One quick question, what's the story with the RGBA byte ordering across all the different platforms? Specifically, can I assume a particular byte order so that I can generate the RGBA in place in my own byte[]? That way I can avoid the need to use a Color[] and then ConvertColorToRgb (which generates garbage) to get the byte[]. Texture.ConvertColorToRgb doesn't seem to do any platform checks, so the byte order looks to be always red, then green, etc.


You don't need to call ConvertColorToRgb, it is just a helper in case someone is working with colors (it makes the unit tests a bit easier to understand). You can check out the code of ConvertColorToRgb in the Texture.cs file, there is no magic going on. You can create and manage your own byte buffers for your own dynamic textures if you like.

To be honest it is even a little bad to do it like I did in the new UpdateTextureData test above because each frame a new byte buffer is created unnecessarily. Just keeping one single byte array around and filling it with different data is much more efficient and won't stress the GC on mobile platforms.

Note: Currently only RGB and RGBA formats are supported (as you say in the red, green, blue order), but if you need more you can easily extend the methods. For example it would be possible to fill DXT data dynamically, but compressing will take some CPU so it is probably not worth the effort. A format like RGBA4 (all 4 bit, thus 16 bit = 2 bytes in total instead of 4 bytes) could make more sense if texture bandwidth is a problem and 4 bit is enough color depth (all supported in all OpenGL, XNA and DirectX platforms).

Edited by user Tuesday, May 1, 2012 10:41:39 PM(UTC)  | Reason: Not specified

Offline fool  
#5 Posted : Wednesday, May 2, 2012 12:51:46 PM(UTC)
fool

Joined: 8/24/2011(UTC)
Posts: 34
Location: New Zealand

Thanks: 4 times
Originally Posted by: Benjamin Nitschke (DeltaEngine) Go to Quoted Post
Byte ordering is also not a problem because .NET code behaves the same on all platforms (always little-endian, if you are interested). I don't think there is even any code in the Delta Engine caring about this ^^

Nice to know it's not a problem so far, but I did hit an endian issue using XNA and DynamicSoundEffectInstance on the Xbox 360.

Anyway, thanks to your latest addition I quickly got the video rendering for my project. See the attached screenshot.

Now on to the sound, which no doubt will require another request. ;)
fool attached the following image(s):
Jellyfish.Virtu.Delta.jpg (156kb) downloaded 10 time(s).

You cannot view/download attachments. Try to login or register.
Rss Feed  Atom Feed
Users browsing this topic
OceanSpiders 2.0
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF.NET | YAF.NET © 2003-2023, Yet Another Forum.NET
This page was generated in 0.082 seconds.