-
Hi all, I'm in the process of converting my game engine from c++ to c#, mainly because I want to use WinForms, I tried using QT in c++ but it was much harder, also because I'm currently debating whether or not I should learn c++ or C# for Object Oriented Programming next semester (thoughts? :P).
Anyway, this line here:
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
is giving me trouble.
If i make it simply a vertex, I can't do quad[0], quad[1], etc, as per:
quad
[0].Position = new Vector2f
(i
* tileSize
.X, j
* tileSize
.Y); quad
[1].Position = new Vector2f
((i
+ 1) * tileSize
.X, j
* tileSize
.Y); quad
[2].Position = new Vector2f
((i
+ 1) * tileSize
.X,
(j
+ 1) * tileSize
.Y); quad
[3].Position = new Vector2f
(i
* tileSize
.X,
(j
+ 1) * tileSize
.Y);
Note that I've put it in C# syntax, the c++ syntax is basically the same.
If I make it a vertex[], then that doesn't work either because it tries to convert from Vertex to Vertex[];
Vertex[] quad = m_vertices[(i + j * width) * 4];
I have no idea how I can do this. Since safe c# can't use pointers or reference, I don't know how I can get this to work.
Can someone please show how I can get this specific part of code to work?
Thanks.
-
Use indices instead of pointers.
uint index = (i + j * width) * 4;
m_vertices[index + 0].Position = ...;
m_vertices[index + 1].Position = ...;
m_vertices[index + 2].Position = ...;
m_vertices[index + 3].Position = ...;
-
Thanks, I tried that, however now I'm getting this error:
Error 1 Cannot modify the return value of 'SFML.Graphics.VertexArray.this[uint]' because it is not a variable C:\Users\Kevin Mallinson\Documents\Visual Studio 2012\Projects\MapMakerDotNet\MapMakerDotNet\TileMap.cs 92
This is how I implemented it:
m_vertices
[index
+ 0].Position = new Vector2f
(i
* tileSize
.X, j
* tileSize
.Y);m_vertices
[index
+ 1].Position = new Vector2f
((i
+ 1) * tileSize
.X, j
* tileSize
.Y);m_vertices
[index
+ 2].Position = new Vector2f
((i
+ 1) * tileSize
.X,
(j
+ 1) * tileSize
.Y);m_vertices
[index
+ 3].Position = new Vector2f
(i
* tileSize
.X,
(j
+ 1) * tileSize
.Y);
Do you know why that's happening? It's strange...
-
Ah, yes. Vertex is a structure, operator [] returns a copy. You have to overwrite the whole vertex (m_vertices[a] = new Vertex(...)).
-
Thanks, it compiles fine now:
m_vertices[index + 0] = new Vertex(new Vector2f(i * tileSize.X, j * tileSize.Y), new Vector2f(tu * tileSize.X, tv * tileSize.Y));
m_vertices[index + 1] = new Vertex(new Vector2f((i + 1) * tileSize.X, j * tileSize.Y), new Vector2f((tu + 1) * tileSize.X, tv * tileSize.Y));
m_vertices[index + 2] = new Vertex(new Vector2f((i + 1) * tileSize.X, (j + 1) * tileSize.Y), new Vector2f((tu + 1) * tileSize.X, (tv + 1) * tileSize.Y));
m_vertices[index + 3] = new Vertex(new Vector2f(i * tileSize.X, (j + 1) * tileSize.Y), new Vector2f(tu * tileSize.X, (tv + 1) * tileSize.Y));
That is how I've implemented it.
Also, one more thing: Since I'm basing my class off the vertex array tutorial, which inherets Drawable and Transformable, and i'm using c#, I can't inheret more than one class.
So I simply instantiated Transformable inside the class, so I can access the method to get the transform:
states.Transform *= TransformInstance.Transform;
Do you think that would work? Note that I can't test it right now since I'm making sure all the code compiles before linking it all up and whatnot :/.
-
Since I'm basing my class off the vertex array tutorial, which inherets Drawable and Transformable, and i'm using c#, I can't inheret more than one class.
Drawable is an interface, and in C# you can inherit as many interface as you want in addition to another base class. Look at SFML drawable classes, they all inherit both Drawable and Transformable. So there's no problem.
-
Ah, okay thanks :)
So i've successfully converted my program from c++ to c#. I've noticed that in c++ it uses 10% cpu, in c# it uses about 30%. That's something I'll have to look in to, perhaps I'm doing something wrong.
There's one thing I was slightly confused about:
The way that I can implement the Draw function from the Drawable interface is like this:
void Drawable.Draw(RenderTarget target, RenderStates states)
whereas in c++ i can do it like this:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
Notice that in c++ i can pass the target by reference, but I can't do that in c#. I tried, but it says I'm not implementing the interface when I do it like this:
void Drawable.Draw(ref RenderTarget target, RenderStates states)
Couldn't this perhaps cause a slight inefficiency, if it has to pass by value and copy the target each time It's called? Or am I misinterpreting this?
Thanks! :)
-
In C# all class instances are hidden pointers. You don't need to pass them by reference.
-
In C# all class instances are hidden pointers. You don't need to pass them by reference.
Ah, okay thanks.
-
Hi, sorry for bothering you again! >_< anyway, I did some profiling on my C# program (it uses 20% CPU, I have an i7) whereas my c++ version of the same program uses about 5-8% CPU.
I ran the visual studio profiler and according to that this is what is causing most of the cpu usage:
m_vertices
[index
+ 0] = new Vertex
(new Vector2f
(i
* tileSize
.X, j
* tileSize
.Y),
new Vector2f
(tu
* tileSize
.X, tv
* tileSize
.Y)); m_vertices
[index
+ 1] = new Vertex
(new Vector2f
((i
+ 1) * tileSize
.X, j
* tileSize
.Y),
new Vector2f
((tu
+ 1) * tileSize
.X, tv
* tileSize
.Y)); m_vertices
[index
+ 2] = new Vertex
(new Vector2f
((i
+ 1) * tileSize
.X,
(j
+ 1) * tileSize
.Y),
new Vector2f
((tu
+ 1) * tileSize
.X,
(tv
+ 1) * tileSize
.Y)); m_vertices
[index
+ 3] = new Vertex
(new Vector2f
(i
* tileSize
.X,
(j
+ 1) * tileSize
.Y),
new Vector2f
(tu
* tileSize
.X,
(tv
+ 1) * tileSize
.Y));
I think I may know why, it's because I'm creating everything with new, as that's the only way I think it will work, instead of just editing the existing value.
Perhaps I'm being inefficient by calling this every main loop. I THINK I could use a conditional to call it only when the map is changed. In fact, I'll do that after I post this.
However, I was wondering if theres a more efficient way of doing what I've enclosed in the code tags, without using new to save cpu resources?
Thanks! :)
-
However, I was wondering if theres a more efficient way of doing what I've enclosed in the code tags, without using new to save cpu resources?
With a VertexArray, no. But with your own storage (like a Vertex[]), yes, I think you would be able to modify vertices directly.
-
Okay, thanks! :)
I'll try to implement that.
and p.s. i save about 5% CPU by only calling it when the map is updated, which is good.
Thanks :)
-
Oh, one more question, if you don't mind. I'm sorry for asking so much questions, I just love using SFML and am a beginner still with it :)
p.s. Sorry for double posting, I'm not sure if editing would notify readers that there is a message unread(?).
I'm trying to get my memory usage down now, as It's using 60MB, which is quite high since my program is still small-ish.
I profiled the memory usage and it came up with this:
http://i.imgur.com/n12iB8s.png
I'm not sure why views are using a lot of memory, as I remember reading in the tutorial that they're lightweight. Since it says GetView is using the most memory, I'll show you the function that uses GetView:
public int change_current_tile_temp(ref RenderWindow window, ref int tile)
{
Vector2f mouse = window.MapPixelToCoords(Mouse.GetPosition(window));
float[] ViewSize = {window.GetView().Size.X, window.GetView().Size.Y};
//std::cout << "Mouse X Versus View Size: " << mouse.x << " VS " << XYSIZE * TILE_SIZE << std::endl;
if (mouse.X > ViewSize[0] - ViewSize[0] &&
mouse.X < Constants.XYSIZE * Constants.TILE_SIZE &&
mouse.Y < Constants.XYSIZE * Constants.TILE_SIZE &&
mouse.Y > ViewSize[1] - ViewSize[1]
&& Mouse.IsButtonPressed(Mouse.Button.Left)
)
{
int mouseX = (int)mouse.X / Constants.TILE_SIZE;
int mouseY = (int)mouse.Y / Constants.TILE_SIZE;
tile = mouseX + mouseY * Constants.XYSIZE;
//std::cout << "pressed tile: " << tile << std::endl;
}
return tile;
}
This is called once every tick of the main loop. It checks if the mouse is in the view window, and then if it is, and you pess the mouse down, it gets what tile you clicked, and returns it.
Do you know why this might be apparently using a lot of memory?
Thanks! :)
Edit: Oh, by the way, the reason I'm using an array to store the X and Y which may seem redundant is because I was checking if calling GetView two times per tick instead of four would make a difference.. It didn't make a difference unfortunately.
-
Sorry for double posting, I'm not sure if editing would notify readers that there is a message unread(?)
Yes there's a notification. But anyway, editing or posting a new message leads to the same result (new message to read), so don't worry so much about that ;)
I don't think that views are directly causing half of your memory usage. I would say it's something different, which somehow shows up as "views" in your report.
Memory usage can be very high even if you're not doing anything in your program, this is generally caused by the graphics driver itself, which allocates and runs a lot of hidden stuff. You should first compare your own program with a minimal one (i.e. a window with a main loop). Maybe the memory usage of the minimal program will already be quite high.
-
Thanks for that tip, in a minimal example, rendering nothing, it just having a blank window open and refreshing it, it uses 40MB. So the memory of my program is about 20mb, i guess.
It thinks this is the function with the most allocated memory in the minimal example:
Functions Allocating Most Memory
Name Bytes %
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(native int,int32,int32) 43.04
I'm not really sure what that is, lol.
Anyway, in relation to the earlier posts of this thread, I tried using a Vertex[] instead of VertexArray. I can get it to render just fine when I use the new function to create the new vertex to display, however, if I don't use the new function, it just doesn't work for some reason.
In the code below, the first set of code succeeding the commented section works, the next part doesn't work. In the second part I used the new function to create the Vector2f, so in the third example I got rid of the new function all together just to rule out that as a cause.
//WORKS
testVertexArray[index + 0] = new Vertex(new Vector2f(i * tileSize.X, j * tileSize.Y), new Vector2f(tu * tileSize.X, tv * tileSize.Y));
testVertexArray[index + 1] = new Vertex(new Vector2f((i + 1) * tileSize.X, j * tileSize.Y), new Vector2f((tu + 1) * tileSize.X, tv * tileSize.Y));
testVertexArray[index + 2] = new Vertex(new Vector2f((i + 1) * tileSize.X, (j + 1) * tileSize.Y), new Vector2f((tu + 1) * tileSize.X, (tv + 1) * tileSize.Y));
testVertexArray[index + 3] = new Vertex(new Vector2f(i * tileSize.X, (j + 1) * tileSize.Y), new Vector2f(tu * tileSize.X, (tv + 1) * tileSize.Y));
//DOESNT WORK
testVertexArray[index + 0].Position.X = i * tileSize.X;
testVertexArray[index + 0].Position.Y = j * tileSize.Y;
testVertexArray[index + 1].Position.X = (i + 1) * tileSize.X;
testVertexArray[index + 1].Position.Y = j * tileSize.Y;
testVertexArray[index + 2].Position.X = (i + 1) * tileSize.X;
testVertexArray[index + 2].Position.Y = (j + 1) * tileSize.Y;
testVertexArray[index + 3].Position.X = i * tileSize.X;
testVertexArray[index + 3].Position.Y = (j + 1) * tileSize.Y;
testVertexArray[index + 0].TexCoords.X = tu * tileSize.X;
testVertexArray[index + 0].TexCoords.Y = tv * tileSize.Y;
testVertexArray[index + 1].TexCoords.X = (tu + 1) * tileSize.X;
testVertexArray[index + 1].TexCoords.Y = tv * tileSize.Y;
testVertexArray[index + 2].TexCoords.X = (tu + 1) * tileSize.X;
testVertexArray[index + 2].TexCoords.Y = (tv + 1) * tileSize.Y;
testVertexArray[index + 3].TexCoords.X =tu * tileSize.X;
testVertexArray[index + 3].TexCoords.Y = (tv + 1) * tileSize.Y;
//DOESNT WORK
testVertexArray[index + 0].Position = new Vector2f(i * tileSize.X, j * tileSize.Y);
testVertexArray[index + 1].Position = new Vector2f((i + 1) * tileSize.X, j * tileSize.Y);
testVertexArray[index + 2].Position = new Vector2f((i + 1) * tileSize.X, (j + 1) * tileSize.Y);
testVertexArray[index + 3].Position = new Vector2f(i * tileSize.X, (j + 1) * tileSize.Y);
testVertexArray[index + 0].TexCoords = new Vector2f(tu * tileSize.X, tv * tileSize.Y);
testVertexArray[index + 1].TexCoords = new Vector2f((tu + 1) * tileSize.X, tv * tileSize.Y);
testVertexArray[index + 2].TexCoords = new Vector2f((tu + 1) * tileSize.X, (tv + 1) * tileSize.Y);
testVertexArray[index + 3].TexCoords = new Vector2f(tu * tileSize.X, (tv + 1) * tileSize.Y);
Sorry that it's quite lengthy, but it's essentially all the same thing, just rewritten. I'm not sure why this isn't working. Do you have any idea?
Thanks!
-
It must be the same reason why very first code didin't work: operator[] returns a copy of the vertex, even in a native array.
-
It must be the same reason why very first code didin't work: operator[] returns a copy of the vertex, even in a native array.
Dang. I think I could get this to work by using unsafe code but I don't really want to do that. I tried using lists to get it to work but again couldn't figure that out (since I've never used lists before).
Do you have any ideas? Or do you think I should just use unsafe code if I want it to be as efficient as possible?
-
I don't think you can do better than your current code. Don't focus too much on this, this is not a real problem.
-
I don't think you can do better than your current code. Don't focus too much on this, this is not a real problem.
Alright, I guess you're right, and maybe my optimizations are premature, maybe these are the things that are going to take the bulk of the CPU usage anyway, the rest of my engine would just "sit on top of it", for the lack of better words. And that kind of makes sense because the renderer probably is what would take the most CPU usage.
I'm just worried my program will have high CPU usage, but I guess i'll implement more stuff before worrying about it :)
Thanks for the help :)
-
Do you activate vertical synchronization in your program?
-
Do you activate vertical synchronization in your program?
I set vertical sync to enabled on my RenderWindow, however I'm using the handle of a panel in WinForms.
After your comment i checked fraps and in fact the window is at 500 FPS, I'm not sure, however, if that means that my main loop is being executed far too many times, since I did apply vertical sync to the RenderWindow.
I'll try and see if I can figure out how to limit the framerate of the WinForm.
-
I'll try and see if I can figure out how to limit the framerate of the WinForm.
Check your graphics driver settings to see if you can force VSync on. If that doesn't change your FPS then try disabled VSync and using SFML's set framerate limit function.
-
Tried all of that and it doesn't change my fps unfortunately.
-
How do you trigger refresh cycles for your widget? A fixed timer? A "repaint" event?
-
How do you trigger refresh cycles for your widget? A fixed timer? A "repaint" event?
Well, I don't really rely on events from the winforms to do the refreshing; only for other things (like responding to button click events etc)
So, in the form_load function I initiate the window and loop:
I *think* form_load function is called only once, on initial startup.
private void Form1_Load
(object sender, EventArgs e
) { Init
(); //create the window to bind to the form SFMLWindow
= new RenderWindow
(this.Handle); // Create the SFMLWindow from the handle of any control. In this example we will use our current forms handle //SFMLWindow.SetVerticalSyncEnabled(true); //SFMLWindow.SetFramerateLimit(60); //start the game loop MainLoop
(); }
In my main loop, I do all the normal stuff, but use while formopen instead of the normal way, as It didn't seem to work, probably because it's within a form:
while (FormOpen)
{
ProcessInput();
window.Clear(SFML.Graphics.Color.White);
...
}
Perhaps I could use a timer to only have it called 60 times per second, I'll look in to that.
-
You're running your game loop in Form1_Load, so it never returns? ???
Are your window & other widgets responsive? Everything works fine??
-
Yeah everything is responsive and runs fine. I'm not running my game loop from Form1_Load, I'm calling it there though. I should probably have specified that my Form1 class is also serving as my 'Engine' class to which everything else is created.
Here's a video showing what it working:
http://www.youtube.com/watch?v=WCV0V2fSpEs&feature=youtube_gdata
p.s. what exactly do youm ean by "so it never returns?"?
-
what exactly do youm ean by "so it never returns?
Because of this:
while (FormOpen)
So whoever calls Form1_Load (the UI thread or whatever) will never see this call end, and do whatever has to be done after it.
When you integrate SFML into a UI, you should not run a blocking main loop. You should rather use a timer or the repaint event to refresh your SFML view, while not blocking the main flow of the application (which is most likely already driven by the main UI system and internal events).
-
Ah, Okay. So I think I understand what your saying:
Because I've implemented my loop in Form1_Load, which will only stop looping if the form is closed, nothing will ever be executed below the loop, so the function can never exit and return void; and some events may be waiting for Form1_Load to return void.
Instead, I should use a main loop in a less traditional sense; have no while loop at all, instead rely on constantly firing events to execute my game code, such as the ReDraw event. If i put my loop inside the ReDraw event function, it essentially acts as a loop as ReDraw is always being called.
OR, use a Timer and in the timer_tick (or whatever its called) implement my loop there (again, without a technical while loop)
Did I interpret that correctly?
-
Did I interpret that correctly?
Absolutely ;)
-
Alright, thanks.
So what I've done is whenever the window is activated, the timer is set to true, otherwise, it's set to false.
Then, I do my drawing in the timer tick function. I set the interval of Timer Tick to 1; but it still does not call anywhere near as often as my while loop did. However, this works for me as because it doesn't tick often, it gives me an effective framerate of 64 FPS.
However, Because my game doesn't draw at 500 fps anymore, It's quite jumpy to move the view so i can see all parts of the map.
Previously this would result in a clean movement of the map:
if (Keyboard
.IsKeyPressed(Keyboard
.Key.Left)) view
.Move(new Vector2f
(1
.25f,
0));
However, the only way I can produce a scrolling speed that I'm happy with is to do this:
if (Keyboard
.IsKeyPressed(Keyboard
.Key.Left)) view
.Move(new Vector2f
(10
.0f,
0));
But it is quite 'jumpy', so I need a way to smooth it out. Since my timer is a millisecond timer, and I already have it set to 1, that's as fast as I can get the timer to tick.
Do you have any idea how I could do this?
P.S. by doing this, I've got my engine down from 12-17% CPU usage to less than 0.1% CPU usage.
-
Hum... 60 FPS should be enough to achieve smooth movements, I don't know why it's jumpy.
But are you really moving your view of 600 units per second? It's seem a lot -- unless the view is zoomed out.
By the way, you should probably not use Keyboard.IsKeyPressed, because that will make your view move even if your window doesn't have the focus.
-
Yeah I'm zoomed in when I'm trying to move it like that, I think i'll use a scrollbar or something from windows forms and implement a variable to position the middle of the view relative to the scrollbar, or something...
haha.
-
Hey, I have one more question if that's okay:
Since editing my code greatly to try and improve the speed, etc (I didn't save a backup :/) I've now been getting this error:
$exception
{System.AccessViolationException: Attempted to read or write
protected memory
. This is often an indication that other memory
is corrupt
.at SFML
.Graphics.Context.sfContext_create()at SFML
.Graphics.Context..ctor()at SFML
.Graphics.Context.get_Global()at SFML
.Graphics.Texture.Destroy(Boolean disposing
)at SFML
.ObjectBase.Dispose(Boolean disposing
)at SFML
.ObjectBase.Finalize()}
I only get this error on exit. It doesn't affect my program at all, I just can't exit without getting the error.
It seems to reference Graphics and ObjectBase a lot, however I have no idea what is causing the error, so I can't make a complete and minimal example. Do you have any idea what might be causing this?
Otherwise, I guess i'll have to backtrack and remove code until it stops getting the error, and re-add that part.
Thanks.
-
I have no idea, sorry.
-
Alright, well i guess i can always just do this until I decide I want to fix it, lol.
private void OnProcessExit(object sender, EventArgs e)
{
//crashes on exit if i dont do this
Environment.Exit(1);
}
-
at SFML.Graphics.Context.sfContext_create()
at SFML.Graphics.Context..ctor()
at SFML.Graphics.Context.get_Global()
at SFML.Graphics.Texture.Destroy(Boolean disposing)
at SFML.ObjectBase.Dispose(Boolean disposing)
at SFML.ObjectBase.Finalize()}
Your error is happening when a texture is being disposed by the garbage collector. When the GC disposes SFML objects Laurent attempts to create a SFML context to ensure there is still an active context to dispose of the OpenGL resources. See this topic (http://en.sfml-dev.org/forums/index.php?topic=11772.0) for more information there. However you can ensure SFML will never attempt to create contexts as long as you call sfmlObject.Dispose() on all of your SFML objects.
When you do your cleanup be sure you call Dispose() on all of your textures/font/rendertextures before letting your program exit.
On a side note you should seriously consider creating a git repository in your source code directory. And then it will be super easy to go see what you changed :D You could even open a free account on BitBucket and push your source code there for additional safety and backups. I recommend BitBucket for unlimited private repos and Github for public repos.
-
Alright thanks, when i get a working version I think i'll upload that on GitHub and make revisions so I don't end up in the same situation and I can debug when something bad happens.
I started Implementing IDisposable to try and fix the problem. Dispose calls ReleaseManagedResources().
And I indeed found exactly where my error comes from:
void ReleaseManagedResources()
{
Console.WriteLine("Releasing Managed Resources");
if (MVertices != null)
{
MVertices.Dispose();
}
if (MTileset != null)
{
MTileset.Dispose();
//Exception - Attempted to read or write on protected memory.
}
if (TransformInstance != null)
{
TransformInstance.Dispose();
}
}
MTileset is a Texture. I don't change MTileset in any way.
Any ideas? If not; i'll try and make a small example with the error happening.
Edit: This also happens when I try to dispose of a VertexArray, but my program doesn't crash; it only crashes with the texture.
http://i.imgur.com/dkssvv9.png
Edit 2: I seem to have fixed it. Instead of disposing it when I don't need it anymore, I dispose it inside the WinForms dispose method, and it fixes it, my only hypothesis of why this fixes it is because even though it was disposed, the checks done by SFML somehow referenced it and tried to read it in some way, so by disposing it after everything else fixes it because there's now nothing to check
...or something.