Why is my mesh only displayed every second frame? - directx

I'm trying to draw a single triangle on-screen using SharpDX (DX11). For whatever reason, the triangle only seems to be drawn every second frame. My device initialization code looks like this:
public void Init()
{
renderForm = new RenderForm(Engine.GameTitle);
renderForm.ClientSize = new Size(Engine.Settings.Screen.Width, Engine.Settings.Screen.Height);
renderForm.MaximizeBox = false;
var desc = new SwapChainDescription()
{
BufferCount = 2,
ModeDescription = new ModeDescription(renderForm.ClientSize.Width, renderForm.ClientSize.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = renderForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Sequential,
Usage = Usage.RenderTargetOutput
};
Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
deviceContext = device.ImmediateContext;
var factory = swapChain.GetParent<Factory>();
factory.MakeWindowAssociation(renderForm.Handle, WindowAssociationFlags.IgnoreAll);
backBuffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
renderView = new RenderTargetView(device, backBuffer);
backBuffer.Dispose();
deviceContext.OutputMerger.SetTargets(renderView);
deviceContext.Rasterizer.SetViewports(new Viewport(0, 0, renderForm.ClientSize.Width, renderForm.ClientSize.Height, 0.0f, 1.0f));
ProjectionMatrix = Matrix.PerspectiveFovLH(
(float)(Math.PI / 4),
(float)(renderForm.ClientSize.Width / renderForm.ClientSize.Height),
nearPlane,
farPlane);
WorldMatrix = Matrix.Identity;
renderForm.Location = new Point(Screen.PrimaryScreen.Bounds.Width / 2 - Engine.Settings.Screen.Width / 2, Screen.PrimaryScreen.Bounds.Height / 2 - Engine.Settings.Screen.Height / 2);
}
The code for rendering the triangle looks like this:
public void Render()
{
DeviceContext context = D3DRenderer.Instance.GetDevice().ImmediateContext;
context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, Utilities.SizeOf<Vertex>(), 0));
context.InputAssembler.SetIndexBuffer(IndexBuffer, Format.R32_UInt, 0);
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
}
public void RenderShader(int indexCount)
{
device.ImmediateContext.DrawIndexed(indexCount, 0, 0);
}
Whereas Render() is called before RenderShader().
There's no error message returned by any function except for an Direct3D warning:
D3D11: WARNING: ID3D11DeviceContext::DrawIndexed: The size of the Constant Buffer at slot 0 of the Vertex Shader unit is too small (64 bytes provided, 192 bytes, at least, expected).
My MatrixBuffer structure looks like the following:
[StructLayout(LayoutKind.Sequential)]
internal struct MatrixBuffer
{
public Matrix world;
public Matrix view;
public Matrix projection;
}
I have been clearing the backbuffer every other frame with a different color to make sure it's not an issue with not correctly swapping the backbuffer. This is working fine.
I am quite baffled as to why this isn't working right now. I hope anyone knows an answer to this.

Ladies and gentleman, learn a lesson today.. Never copy and paste tutorial code. Ever.
Turns out the issue was in the shader rendering code. The tutorial I copied the declarations from (and didn't post on here, otherwise it might've been pretty obvious to you guys) had the world/view/projection matrices declared as follows:
public Matrix WorldMatrix { get; private set; }
Then I tried to do this:
D3DRenderer.Instance.WorldMatrix.Transpose();
Which for now obvious reasons doesn't work. Interestingly it did seem to work every other frame. Why that is I have no idea. But after changing the matrix definitions from private set to set everything is now working fine.

Related

classify new image on trained custom model in deeplearning4j (convolutional network)

Im new to deeplearning4J. I already experimented with its word2vec functionality and everything was fine. But now I am little bit confused regarding image classification. I was playing with this example:
https://github.com/deeplearning4j/dl4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/convolution/AnimalsClassification.java
I changed the "save" flag to true and my model is stored into model.bin file.
Now comes the problematic part (I am sorry if this sounds as silly question, maybe I am missing something really obvious here)
I created separate class called AnimalClassifier and its purpose is to load model from model.bin file, restore neural network from it and then classify single image using restored network. For this single image I created "temp" folder -> dl4j-examples/src/main/resources/animals/temp/ where I put picture of polar bear that was previously used in training process in AnimalsClassification.java (I wanted to be sure that image would be classified correctly - therefore I reused picture from "bear" folder).
This my code trying to classify polar bear:
protected static int height = 100;
protected static int width = 100;
protected static int channels = 3;
protected static int numExamples = 1;
protected static int numLabels = 1;
protected static int batchSize = 10;
protected static long seed = 42;
protected static Random rng = new Random(seed);
protected static int listenerFreq = 1;
protected static int iterations = 1;
protected static int epochs = 7;
protected static double splitTrainTest = 0.8;
protected static int nCores = 2;
protected static boolean save = true;
protected static String modelType = "AlexNet"; //
public static void main(String[] args) throws Exception {
String basePath = FilenameUtils.concat(System.getProperty("user.dir"), "dl4j-examples/src/main/resources/");
MultiLayerNetwork multiLayerNetwork = ModelSerializer.restoreMultiLayerNetwork(basePath + "model.bin", true);
ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator();
File mainPath = new File(System.getProperty("user.dir"), "dl4j-examples/src/main/resources/animals/temp/");
FileSplit fileSplit = new FileSplit(mainPath, NativeImageLoader.ALLOWED_FORMATS, rng);
BalancedPathFilter pathFilter = new BalancedPathFilter(rng, labelMaker, numExamples, numLabels, batchSize);
InputSplit[] inputSplit = fileSplit.sample(pathFilter, 1);
InputSplit analysedData = inputSplit[0];
ImageRecordReader recordReader = new ImageRecordReader(height, width, channels);
recordReader.initialize(analysedData);
DataSetIterator dataIter = new RecordReaderDataSetIterator(recordReader, batchSize, 0, 4);
while (dataIter.hasNext()) {
DataSet testDataSet = dataIter.next();
String expectedResult = testDataSet.getLabelName(0);
List<String> predict = multiLayerNetwork.predict(testDataSet);
String modelResult = predict.get(0);
System.out.println("\nFor example that is labeled " + expectedResult + " the model predicted " + modelResult + "\n\n");
}
}
After running this, I get error:
java.lang.UnsupportedOperationException
at org.datavec.api.writable.ArrayWritable.toInt(ArrayWritable.java:47)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.getDataSet(RecordReaderDataSetIterator.java:275)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:186)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:389)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:52)
at org.deeplearning4j.examples.convolution.AnimalClassifier.main(AnimalClassifier.java:66)
Disconnected from the target VM, address: '127.0.0.1:63967', transport: 'socket'
Exception in thread "main" java.lang.IllegalStateException: Label names are not defined on this dataset. Add label names in order to use getLabelName with an id.
at org.nd4j.linalg.dataset.DataSet.getLabelName(DataSet.java:1106)
at org.deeplearning4j.examples.convolution.AnimalClassifier.main(AnimalClassifier.java:68)
I can see there is a method public void setLabels(INDArray labels) in MultiLayerNetwork.java but I don't get how to use (especially when it takes as argument INDArray).
I am also confused why I have to specify number of possible labels in constructor of RecordReaderDataSetIterator. I would expect that model already knows which labels to use (should not it use labels that were used during training automatically?). I guess, maybe I am loading the picture in completely wrong way...
So to summarize, I would like to achieve simply following:
restore network from model (this is working)
load image to be classified (also working)
classify this image using the same labels that were used during training (bear, deer, duck, turtle) (tricky part)
Thank you in advance for your help or any hints !
So summarizing your multiple questions here:
A record for images is 2 entries in a collection. The second 1 is the label. The label index is relative to the kind of record you pass in.
The second part of your question:
Multiple entries can be apart of a dataset. The list refers to a label for an item at a particular row in the minibatch.

Saving bmp image multiple times on the same path C#

So, I'm working on my paint application. Every time I make changes, the current screen state is copied and saved as a bitmap image on my disk (so I can use it in my paint event).
The problem occurs when I minimize and return the window to its normal state and then try to draw. This triggers my event reacting to changes, the program tries to save the image ---->>> kabooom.
It says "A generic error occurred in GDI+".. So, I've been surfing through various forums in search for the answer but none of them gave me true answer, they all mention wrong paths etc. but I'm pretty sure that's not the problem. Do I have to dispose bitmap or do something with the stream?
int width = pictureBox1.Size.Width;
int height = pictureBox1.Size.Height;
Point labelOrigin = new Point(0, 0); // this is referencing the control
Point screenOrigin = pictureBox1.PointToScreen(labelOrigin);
int x = screenOrigin.X;
int y = screenOrigin.Y;
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(width, height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, bounds.Size);
}
bitmap.Save(_brojFormi + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
You're saving an image to disk so you can use it in another event? Wow.
Why not just use a class-global variable to store the bitmap?
class MyForm
{
Bitmap currentImage = null;
Graphics gfx = null;
private void btnLoad_Click(object sender, EventArgs e)
{
// ...
currentImage = new Bitmap(fileName);
gfx = Graphics.FromImage(currentImage);
}
private void pbEditor_Paint(object sender, PaintEventArgs e)
{
if (currentImage != null && gfx != null)
{
lock(currentImage) e.Graphics.DrawImage(currentImage, ...);
}
}
private void pbEditor_Click(object sender, MouseEventArgs e)
{
// quick example to show bitmap drawing
if (e.Button == MouseButtons.Left)
lock(currentImage) currentImage.SetPixel(e.Location.X, e.Location.Y, Colors.Black);
}
}

Away3D 4.0 Loading dynamic textures for primitives from arrays

I have several arrays storing the attributes needed to build primitives. One array stores the widths, another stores the heights, another the depths, x, y, z etc. I have one more that stores the remote filename for the texture to be applied. After I get my response from the server I attempt to apply the textures to the primitives. When I move the camera to look at the primitive, I am not able to see it. My view seems to freeze up (the view will not update). Once the camera has moved past the primitive, it can see again. Any ideas?
private var loadedBuildingTextures:Object = new Object();
private var map_building_count:Number = 0;
private var loadedBuildings:Number = 0;
public var map_building_widths:Array;
public var map_building_heights:Array;
public var map_building_depths:Array;
public var map_building_xs:Array;
public var map_building_ys:Array;
public var map_building_zs:Array;
public var map_building_textures:Array;
// I POPULATE THE ARRAYS BUT LEFT THAT CODE OUT FOR SIMPLICITY
public function placeBuildings():void {
trace('FUNCTION: placeBuildings() fired');
var buildingsPlaced:Number = 0;
for (var a:Number = 0; a < map_building_count; a++ ) {
loadedBuildingTextures['texture_' + a.toString()] = new BitmapFileMaterial(map_building_textures[a]); // ASSIGNS THE BitmapFileMaterials TO AN OBJECT FOR REFERENCING LATER
loadedBuildingTextures['texture_' + a.toString()].loader.contentLoaderInfo.addEventListener(Event.COMPLETE, postBuildingLoad);
buildingsPlaced++;
}
trace('placed ' + buildingsPlaced.toString() + ' of ' + map_building_count.toString() + ' buildings.'); // OUTPUT = "placed 4 of 4 buildings."
trace('FUNCTION: placeBuildings() completed');
}
public function postBuildingLoad(event : Event):void {
loadedBuildings++;
if (int(loadedBuildings) == int(map_building_count)) {
placeBuildingsStep2();
}
}
public function placeBuildingsStep2():void {
trace('RECEIVED ALL RESPONSES FROM SERVER FOR TEXTURES');
for (var a:Number = 0; a < map_building_count; a++ ) {
cube = new Cube(
loadedBuildingTextures['texture_' + a], // <----- THIS SEEMS TO BE THE PROBLEM
map_building_widths[a], // WIDTH
map_building_heights[a], // HEIGHT
map_building_depths[a], // DEPTH
1, // WIDTH UNITS
1, // HEIGHT UNITS
1, // DEPTH UNITS
true);
cube.x = map_building_xs[a];
cube.y = map_building_ys[a];
cube.z = map_building_zs[a];
view.scene.addChild(cube);
}
}
Although this post is old, it does highlight an important issue. BitmapFileMaterial is more a shortcut to test than a production ready scheme.
I would highly recommend using a loading queue for external assets (like LoaderMax or the new AssetLibrary in 4.0) and then instantiate materials as needed.

Custom XNA Game loop in Windows

I'm trying to figure out how to manage the whole game loop manually in a Windows game, without using the regular Game Microsoft.Xna.Framework.Game class.
The reason for this is using the regular Game class causes some stuttering in my game. Not much, but because of the specific nature of the game it is still quite visible.
After trying a bunch of different settings (vsync, fixedtimestep, various framerates etc.) I decided to try write my own Game class to have full control of the timing. I am not sure that will fix it, but at least this way I have full control.
Basically I need to:
Set up the game window
In a loop: Do all rendering as usual, and then flush the result to the screen, manage backbuffers etc.
Anyone knows how to do this? It sounds quite easy in fact, but could not find any documentation on how to do it.
Not sure what I am doing wrong, but I have the following code (just for testing, timing will be handled differently), and the loop will run for a little while then stop. Once I pass my mousepointer over the window the loop will run for a little while again.
private void Application_Idle(object pSender, EventArgs pEventArgs)
{
Thread.Sleep(500);
//Message message;
//while (!PeekMessage(out message, IntPtr.Zero, 0, 0, 0))
{
gametime.update();
Update(gametime);
Draw(gametime);
GraphicsDevice.Present();
}
}
If enabling the "while PeekMessage", the loop will run continuously, but ignoring the sleep and also stopping when the mouse is moving over the window. Not sure what is going on here...
I think optimally I would just want to do something simple like this in the main render loop:
while (alive)
{
Thread.Sleep(100);
gametime.update();
Update(gametime);
Draw(gametime);
GraphicsDevice.Present();
}
But in this case the window remains blank, as it seems the window is not actually being redrawn with the new content. I tried a form.Refresh(), but still no go... Any ideas?
(added xbox information)
for windows you Basically need to create a Form and Show it, then store its handle and the form itself.
Using this handle you can create a GraphicsDevice.
Then you hook Application.Idle to your own function that calls your update and render.
For example
public class MyGame
{
public Form form;
public GraphicsDevice GraphicsDevice;
public MyGame()
{
form = new Form();
form.ClientSize = new Size(1280, 1024);
form.MainMenuStrip = null;
form.Show();
}
public void Run()
{
PresentationParameters pp = new PresentationParameters();
pp.DeviceWindowHandle = form.Handle;
pp.BackBufferFormat = SurfaceFormat.Color;
pp.BackBufferWidth = 1280;
pp.BackBufferHeight = 1024;
pp.RenderTargetUsage = RenderTargetUsage.DiscardContents;
pp.IsFullScreen = false;
pp.MultiSampleCount = 16;
pp.DepthStencilFormat = DepthFormat.Depth24Stencil8;
GraphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
GraphicsProfile.HiDef,
pp);
Application.Idle += new EventHandler(Application_Idle);
Application.Run(form);
}
private void Application_Idle(object pSender, EventArgs pEventArgs)
{
Message message;
while (!PeekMessage(out message, IntPtr.Zero, 0, 0, 0))
{
/* Your logic goes here
Custom timing and so on
Update();
Render();
*/
}
}
void Render()
{
GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.Black, 1, 0);
//Your logic here.
GraphicsDevice.Present();
}
[StructLayout(LayoutKind.Sequential)]
private struct Message
{
public IntPtr hWnd;
public int msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public Point p;
}
[return: MarshalAs(UnmanagedType.Bool)]
[SuppressUnmanagedCodeSecurity, DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint
messageFilterMin, uint messageFilterMax, uint flags);
}
EDIT 1
For xbox you may just be able to place your own custom run function with your game loop in a throttled while true loop. Inside that run outside the top of the while true you will probably have to do the graphics device initialization and verification with IntPtr.Zero as your handle
EDIT 2
i use something like this ( got from http://www.koonsolo.com/news/dewitters-gameloop/ )
private long nextGameTick;
private Stopwatch stopwatch;
const int ticksPerSecond = 60;
const int skipTicks = 1000 / ticksPerSecond;
private const int maxSkip = 10;
`constructor
stopwatch = Stopwatch.StartNew();
nextGameTick = stopwatch.ElapsedMilliseconds;
`loop
int loops = 0;
long currentTick = stopwatch.ElapsedMilliseconds;
while ( (ulong)(currentTick - nextGameTick) > skipTicks && loops < maxSkip)
{
Update(16.667f);
nextGameTick += skipTicks;
loops++;
}
PreRender();
Render();
PostRender();
EDIT 3
Creating a content manager was a little more work, but still managable. You need to create a class that implements IServiceProvider. This class takes a GraphicsDevice in its constructor in order to create the next class the implements IGraphicsDeviceProvider. in addition I implement GetService like this
//in implementer of IServiceProvider
public object GetService ( Type serviceType )
{
if ( serviceType == typeof ( IGraphicsDeviceService ) )
{
return myGraphicsService;
}
return null;
}
For convenience i also add a method to the class to create and return managers
//in implementer of IServiceProvider
public ContentManager CreateContentManager( string sPath )
{
ContentManager content = new ContentManager(this);
content.RootDirectory = sPath;
return content;
}
In addition i create a class that implements IGraphicsDeviceService and takes a reference to my GraphicsDevice. then I create a property and field in it like so
//in implementer of IGraphicsDeviceService
private GraphicsDevice graphicsDevice;
public GraphicsDevice GraphicsDevice
{
get
{
return graphicsDevice;
}
}
So the call ends up being somehting like
MyServiceProvider m = new MyServiceProvider(graphicsDevice);
ContentManager content = m.CreateContentManager("Content");
where
MyServiceProvider(GraphicsDevice graphicsDevice)
{
myGraphicsService = new MyGraphicsDeviceService(graphicsDevice);
}
MyGraphicsDeviceService(GraphicsDevice gfxDevice)
{
graphicsDevice = gfxDevice;
}
-Sorry for fragmenting the code around but its not something i wrote too recently so im having difficulty remembering parts.
EDIT 4
i had an odd case with my custom game i just remembered when i new the Form for it i
had to bind
private void IgnoreAlt(object pSender, KeyEventArgs pEventArgs)
{
if (pEventArgs.Alt && pEventArgs.KeyCode != Keys.F4)
pEventArgs.Handled = true;
}
to
form.KeyUp += IgnoreAlt;
form.KeyDown += IgnoreAlt;
otherwise i got some horrible stalls.

XNA 4.0 runs at 50 instead of 60 fps

I'm experimenting a bit with XNA 4.0, following tutorials and creating very basic stuff (like a triangle and some lines ;-)). While doing this, I noticed that all my applications never run at more than 50-51 fps (with Fraps). It's not that I'm running heavy programs on a slow computer or graphics card (Ati HD4870), it must have something to do with XNA (games run just fine here).
Now, everything I read about XNA says that the default update frequency is 60 times a second, and I'd like to get that.
It's the same in full screen as in windowed
If I set SynchronizeWithVerticalRetrace to false or true: same
If run the program without Visual Studio, I only get 41 fps
When I override the update frequency by using TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 10); the fps does go up significantly. I noticed though that this still isn't correct: the 10 means 10ms, yet I 'only' get 83 fps instead of 100. At 1ms I get 850 fps. So the deviation of what fps I get and what I should get is pretty consistent. It looks to me like there's just something wrong with the timing?
Anyone knows what might be the problem here and/or has suggestions to get a stable 60 fps?
Thanks!
Isn't it possible that FRAPS isn't giving you accurate results? Have you tried adding in your own framerate counter to the game and seeing what those results say? Shawn Hargreaves has a method he coded up on his blog that should be pretty painless to add to a new blank XNA game project.
http://blogs.msdn.com/b/shawnhar/archive/2007/06/08/displaying-the-framerate.aspx
Do you see the same FPS or is reported differently when you do the calculation yourself?
I put together the following code on XNA 4 and it's getting a locked 60 fps. Try it out on your system (You'll just have to add the appropriate sprite font) and see if you get 60 fps too. If so, put the adjustments in your problem code and see if you get the same result.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace _60fps
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont OutputFont;
float Fps = 0f;
private const int NumberSamples = 50; //Update fps timer based on this number of samples
int[] Samples = new int[NumberSamples];
int CurrentSample = 0;
int TicksAggregate = 0;
int SecondSinceStart = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
graphics.SynchronizeWithVerticalRetrace = false;
int DesiredFrameRate = 60;
TargetElapsedTime = new TimeSpan(TimeSpan.TicksPerSecond / DesiredFrameRate);
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
OutputFont = Content.Load<SpriteFont>("MessageFont");
}
protected override void UnloadContent()
{/* Nothing to do */}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
this.Exit();
base.Update(gameTime);
}
private float Sum(int[] Samples)
{
float RetVal = 0f;
for (int i = 0; i < Samples.Length; i++)
{
RetVal += (float)Samples[i];
}
return RetVal;
}
private Color ClearColor = Color.FromNonPremultiplied(20, 20, 40, 255);
protected override void Draw(GameTime gameTime)
{
Samples[CurrentSample++] = (int)gameTime.ElapsedGameTime.Ticks;
TicksAggregate += (int)gameTime.ElapsedGameTime.Ticks;
if (TicksAggregate > TimeSpan.TicksPerSecond)
{
TicksAggregate -= (int)TimeSpan.TicksPerSecond;
SecondSinceStart += 1;
}
if (CurrentSample == NumberSamples) //We are past the end of the array since the array is 0-based and NumberSamples is 1-based
{
float AverageFrameTime = Sum(Samples) / NumberSamples;
Fps = TimeSpan.TicksPerSecond / AverageFrameTime;
CurrentSample = 0;
}
GraphicsDevice.Clear(ClearColor);
spriteBatch.Begin();
if (Fps > 0)
{
spriteBatch.DrawString(OutputFont, string.Format("Current FPS: {0}\r\nTime since startup: {1}", Fps.ToString("000"), TimeSpan.FromSeconds(SecondSinceStart).ToString()), new Vector2(10,10), Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}

Resources