Using a graphics tablet as a programming tool

2 min. read

I’ve been meaning to share this tip for a while. About one year ago, I discovered a software called Milton. It’s a drawing application that lets you draw on an infinite canvas with an amazing zooming function. It’s incredibly fast and the interface doesn’t get in your way. It turns out it’s really useful for taking notes or thinking about how to solve problems visually. Here is a snapshot of a small portion of the notes I took while working on my game Rashtal:

Rashtal notes
Some of the notes I took while working on my game Rashtal.

To take notes easily, I have the Wacom Bamboo as my graphics tablet. If you don’t have a graphics tablet yet, I’d suggest getting one. Even the cheapest one should do the job perfectly.

Before using Milton, I would use a pen and paper, but for some complex algorithms, I find the infinite canvas to be much easier to work with. Once I’ve been working on a project for a while, the canvas starts to look really impressive.

I find that being able to see all the notes I’ve taken since starting to work on a project really helps me stay motivated. Sometimes I can spend days barely writing any lines of code but then I look at my notes and I can see my thought process and all the planning I went through. Even the simplest lines of code can take a long time to figure out and I tend to forget that.


Thanks for taking the time to read this and good luck with your algorithm planning!

MonoGame Nothing Shader

3 min. read

Okay for this first post, I’m going to keep things simple. Here is a shader that does nothing. We’ll put that in a file called Nothing.fx and load it as content in a MonoGame OpenGL game.

#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

sampler TextureSampler : register(s0);
float2 ViewportSize;
struct VertexToPixel {
    float4 Position : SV_Position0;
    float4 Color : COLOR0;
    float4 TexCoord : TEXCOORD0;
};
VertexToPixel SpriteVertexShader(float4 color : COLOR0, float4 texCoord : TEXCOORD0, float4 position : POSITION0) {
    VertexToPixel Output = (VertexToPixel)0;

    // Half pixel offset for correct texel centering. - This is solved by DX10 and half pixel offset would actually mess it up
    position.xy -= 0.5;

    // Viewport adjustment.
    position.xy /= ViewportSize;
    position.xy *= float2(2, -2);
    position.xy -= float2(1, -1);

    //pass position and color to PS
    Output.Position = position;
    Output.Color = color;
    Output.TexCoord = texCoord;

    return Output;
}

float4 SpritePixelShader(VertexToPixel PSIn): COLOR0 {
    float4 diffuse = tex2D(TextureSampler, PSIn.TexCoord);
    return PSIn.Color * diffuse;
}

technique SpriteBatch {
    pass {
        VertexShader = compile VS_SHADERMODEL SpriteVertexShader();
        PixelShader = compile PS_SHADERMODEL SpritePixelShader();
    }
}
//In LoadContent():
effect = Content.Load<Effect>("Nothing");


//In Draw():
effect.Parameters["ViewportSize"].SetValue(new Vector2(Window.ClientBounds.Width, Window.ClientBounds.Height));
spriteBatch.Begin(effect: effect);
spriteBatch.Draw(image, new Vector2(200, 100), Color.White);
spriteBatch.End();

Note: Not seen but it is implied here that a Texture2D is loaded in the variable “image”.

As you can see, we pass a ViewportSize to the shader and draw the Texture2D using our Nothing shader at a location of 200, 100.


Some information about how shaders work.

sampler TextureSampler : register(s0);

This line receives the “image” Texture2D we gave to the draw call.

float2 ViewportSize;

This line receives the Vector2 passed in using the shader parameters.

SpriteVertexShader(float4 color : COLOR0, float4 texCoord : TEXCOORD0, float4 position : POSITION0)

Here we receive 3 variables in our vertex shader.

position with POSITION0 as the semantic. This means that position uses the screen’s coordinate system. Earlier, in our draw call we passed a Vector2(200, 100). That Vector is used to translate position by 200, 100.

color with COLOR0 as the semantic. This value comes from our draw call. Earlier we passed Color.White. Colors have a value between 0 and 1 in other words, White is (1, 1, 1, 1). The forth parameter is the alpha transparency channel. Note that colors have their alpha premultiplied by default in MonoGame. For example, the color (0.5, 0.5, 0.5, 0.5) is white with 0.5 as the alpha.

texCoord with TEXCOORD0 as the semantic. This one has a mapping of 0 to 1. We use texCoord to sample the texture we received above.

Okay, now we get to the interesting part, the meat of this vertex shader. Turns out this isn’t as complicated as it looks.

// Half pixel offset for correct texel centering. - This is solved by DX10 and half pixel offset would actually mess it up
position.xy -= 0.5;

// Viewport adjustment.
position.xy /= ViewportSize;
position.xy *= float2(2, -2);
position.xy -= float2(1, -1);

So we start with the position variable. This is in screen coordinates. We want to transform this in a different coordinate system. On the X axis, it will go from -1 to 1 and on the Y axis, it will go from 1 to -1. Here is an example for a screen that is 1000px by 500px.

After the transformation, coordinate (0, 0) becomes (-1, 1) and coordinate (1000, 500) becomes (1, -1). This coordinate system is called homogeneous coordinates and it’s what the pixel shader expects later. As you can notice, (0, 0) is the center of the screen.

After that, it’s just a matter of bundling the variables in the VertexToPixel struct and returning that.


float4 diffuse = tex2D(TextureSampler, PSIn.TexCoord);

tex2D is a function that samples the color of a texture at the point TexCoord. Here our texture is “image” which is stored in TextureSampler.

return PSIn.Color * diffuse ;

All this does is it multiplies our diffuse color which we just extracted from our “image” with the color we passed in. That color is White which is 1 therefore the result is simply diffuse. As an exercise, you can try passing in other colors in the draw call with new Color(100, 150, 200)to see how the image’s colors get changed.


That’s it for now! If you see any errors, make sure to tell me in the comments below. Hopefully this can act as a template that can be used to build various shaders.


Further reading: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl

Hello world!

1 min. read

Hello World! This is the first blog post on this site. Actually that’s a lie, I lunched this site back in 2012 when I was working on my own programming language along with a compiler for it from scratch. Back then I would actually post often about my thinking process and how the project was moving along. The code was open sourced and people could check it out.

Since then, time has passed and Vyne has become my company in which I work on programming projects. The current project is a video game called Rashtal. Rashtal is a sort of puzzle game in the canopy of a foreign world. I started working on that project in September 2016.

Anyway, that’s it for me for now, the next article will be about shaders in MonoGame.