November 16, 2011 0

Vignette post process effect

By dominic in HLSL

Vignetting is an effect that can be used to draw the viewer’s attention to the center of the screen, or to add some spookiness to a scene by darkening the contour of the image, or under water rendering for example.

The effect is very simple, it works by taking the distance from a pixel to the center of the screen, and using that distance to modify the pixel color.

The first line of the PS function samples the texture at the given texture coordinates:

float4 color = g_texture.Sample(g_sampler, v.texcoord);

Then we need to map the texture coordinates from [0, 1] to [-.5, .5] by simply subtracting .5 from the texture coordinates. This allows us to know how far the texel is from the center:

float2 dist = v.texcoord - 0.5f;

In this next step, we calculate a factor we will use to scale the color. The closer to the center, the brighter to color, and the further away, the darker it gets. Taking the dot product of the pixel position with itself gives us the squared distance to the center. If we subtract that value to 1, we get a value that starts at 1 when the pixel is at the center of the image and decreases as we move away from the center. Therefore, pixels at the center of the screen will have full intensity:

dist.x = 1 - dot(dist, dist);

The last line is where we actually scale the sample color depending on the distance from the center. We use the saturate function to clamp the resulting color value to [0, 1]:

1
color *= saturate(pow(dist.x, 5.5f));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SamplerState	g_sampler	: register(s0);
Texture2D	g_texture	: register(t0);
 
struct	PS_Input
{
	float4 posH	: SV_POSITION;
	float2 texcoord	: TEXCOORD;
};
 
float4 PS( PS_Input v ) : SV_Target
{
	float4 color = g_texture.Sample(g_sampler, v.texcoord);
	float2 dist = v.texcoord - 0.5f;
	dist.x = 1 - dot(dist, dist);
	color *= saturate(pow(dist.x, 5.5f));
	return color;
}

Post process running on a solid color background:

No post processing applied:

Same image with vignetting:

Tags: ,

November 4, 2011 0

Fast vector truncation

By dominic in AS3.0, C/C++, Lua, Math-physics

Vector truncation is used quite a lot in physics when working with forces. Sometimes if a vector’s length is more than a given maximum length you need to truncate it to the max length allowed. It’s always nice for physics code to run as fast as possible, for reasons we all know.
I’ve seen this vector “truncate” function many times, even in books like this one, written by a guy who seems to know what he is talking about.
Said function looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
void	truncate( t_vec2 *v, float maxLen )
{
  float	vLen;
  float	cLen;
  float	angle;
 
  vLen = v_length(v);
  cLen = (maxLen > vLen) ? vLen : maxLen;
  angle = atan2(v->y, v->x);
  v->x = cos(angle) * cLen;
  v->y = sin(angle) * cLen;
}

Assuming the rest of the code looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct	s_vec2
{
  float	x;
  float	y;
}		t_vec2;
 
float	v_length( t_vec2 *v )
{
  return sqrt(v->x * v->x + v->y * v->y);
}
 
void	truncate( t_vec2 *v, float maxLen )
{
  float	vLen;
  float	cLen;
  float	angle;
 
  vLen = v_length(v);
  cLen = (maxLen > vLen) ? vLen : maxLen;
  angle = atan2(v->y, v->x);
  v->x = cos(angle) * cLen;
  v->y = sin(angle) * cLen;
}

Now that’s cool, it’s slow, but it works. If the length of the vector is more than maxLen, the vector is scaled down to maxLen.
The answer is in the previous line: “If the length of the vector is more than maxLen, the vector is scaled down to maxLen“.
Exactly, it’s SCALED down, so why do the users/coders of that function need a call to atan2, cos and sin ? Why not just scale the vector by the ratio of maxLen of the current vector length ?

By doing just that, the function now looks like this:

1
2
3
4
5
6
7
8
9
void	truncate( t_vec2 *v, float maxLen )
{
  float	s;
 
  s = maxLen / v_length(v);
  s = (s < 1.0f) ? 1.0f : s;
  v->x *= s;
  v->y *= s;
}

The result is less lines of code, less instructions and more speed. It’s also more logical to do it this way.
I’ve compared both functions in C, C++, Lua and AS3.0, and I get a 2x speedup, that’s pretty good.

Tags: , , , ,

September 15, 2011 2

C++/HLSL memory alignment

By dominic in C/C++, Direct3D 11, HLSL

To paraphrase wikipedia, data alignment is the way data is arranged and accessed in computer memory. If you don’t know what and how data alignment works, you should have a read at those links:
Data structure alignment
About data alignment

How this works in HLSL is that data is packed into 4 bytes chunks in such a way that it does not cross a 16 bytes boundary. EsseEssentiallyat this means is that any data type cannot overlap between two chunks of 16 bytes. As an example, a float3 will not be stored like this in memory:

In this case, the float3 is layed out over two chunks, HLSL will not let this happen.
On the other hand, what will happen if you have a structure with two float3 variables is that the first float3 will be placed at memory location 0 (to keep it simple), and the second float3 will not be place right after it at location 3, because this would mean that the y and z components of the second vector would be in a different chunk than the x component. What HLSL does is place the second vector at an aligned memory location, 4, in our case:

So with this in mind, if you have a structure that looks like this:

struct s
{
    float	a;
    float	b;
    float3	c;
};
// total memory: 4 bytes + 4 bytes + 3 * 4 bytes = 20 bytes
// aligned memory: 4 bytes + 4 bytes + 8 "padding" bytes + 4 * 4 bytes = 32 bytes

Variables a and b will be placed one after the other in memory, and c will be placed 8 bytes after b. An extra 4 bytes are added at the end of the structure to pad it in order to keep whatever comes after s from crossing a 16 bytes boundary:

The dark gray boxes show where the padding bytes are placed.
The HLSL documentation has more information and examples on packing rules.

This can be (and is) usefull usefulportant) when using constant buffers in C/C++. When you create a constant buffer and send it to your shader(s), you need to make sure the data inside the buffer is packed in a way that makes sense to HLSL.

Given a struct that looks like this:

struct light
{
    float	a;
    float	s;
    float4	color;
};

We now know that it will look like this in memory:

Once again, the gray boxes are the 8 bytes used for padding.

Now, on the C++ side, the struct holding the data for the buffer would look like this:

struct light
{
    float	a;
    float	s;
    XMFLOAT4	color;
};

While this looks pretty nice and easy, it’s actualy actuallyLet’s say you set the light parameters to be:

light.a = .46f;
light.s = .52f;
light.color = XMFLOAT4(1, 1, 1, 1);

Using the Visual Studio debugger, let’s see what the structure looks like in memory:

0x0013F7C0	0.46000001	0.51999998	1.0000000	1.0000000
0x0013F7D0	1.0000000	1.0000000	-1.0737418e+008	 -1.0737418e+008

As excpecteexpectede the two floating point values followed by our 4 component vector.

If we compare that to the HLSL structure we notice that they do not look the same in memory:
C++:

HLSL:

ThereforThereforee buffer is sent to the GPU, the shader is reading from something that looks like this:

light.a = .46f;	// bytes 0 to 3
light.s = .52f;	// bytes 4 to 7
		// skip 8 padding bytes from the first chunk
light.color = float4(1, 1, ?, ?); // read 16 remaining bytes from the second chunk

This happens because both structures are not aligned the same way. Event more so, the C struct is not aligned at all. So the shader reads the a and s floats from the buffer, and then moves along, ignoring the next 8 bytes to access the float4.
When reading the values for the colour, colorU will gather the second chunk and will build a float4 based on the blue and alpha channels for the red and green components, and will fill the actual blue and alpha components with whatever is in the remaining 8 bytes. This shows that care needs to be taken when using constant buffers.

In order to avoid this type of issue there are a few options:

  1. try and see if you can store the data in an order that will automatiautomatically/li>
  2. you can pad the structure accordingly on your own. For example, instead of having two floats, a vector4 and another float, having the 3 floats one after the other, then adding 4 bytes for padding and having the vector4 be the last member in the structure will save some memory and align the struct.
  3. use __declspec(align(#)) to force a member to be packed on a 16 bytes boundary.
  4. As mentioned by Guille in his comment, you can also use the aligned XMFLOAT*A types, they will avoid you having to use __declspec(align(16)).

In our case, changing the order of the members will always result in the struct being 32 bytes or more, so we can use __declspec(align(16)) to force the XMFLOAT4 to be packed in it’s own chunk, just like what HLSL does to the float4:

struct light
{
    float	a;
    float	s;
    __declspec(align(16)) XMFLOAT4	color;
};

And now, as excpecteexpectedmory looks like this:

// two floating point values + 8 bytes of padding
0x002DF750       0.46000001      0.51999998      0.00000000      0.00000000  
// nicely aligned vector4
0x002DF760       1.0000000       1.0000000        1.0000000       1.0000000

This forces the buffer to be packed like HLSL excpectsexpectsfixes the yellow light problem.

Tags: , , ,

August 17, 2011 0

Using Brownian motion to create a maze

By dominic in C/C++

I needed to generate random mazes for a small project I was working on, and while there are already some nice maze generation algorithms out there that where written by people way smarter than me, I decided to write my own algorithm (partly because I was too lazy to implement an existing one).

The idea is very basic but it works out just fine if you don’t need the most complex and precise maze.
The algorithm starts out by filling the maze (a 2D array) with walls, this just puts an ‘x’ in each grid cell.
In a second pass, it uses simple Brownian motion to “walk” the maze setting the cell it is at with a ‘.’ character, effectively drawing some corridors.

The cool part is that Brownian motion is random, and this creates a bunch of corridors that may or may not end up anywhere close to the maze exit.
In a last pass, a number of waypoints are randomly spawned across the maze. Those points are then sorted based on their x coordinate, and finally a path is drawn from the entrance to the first waypoint, then from the first point to the second, so and so forth until the exit, thus creating a path that leads out of the maze.
This very simple process ends up creating a maze that is guaranteed to have a path from start to finish, as well as adding a bunch of misleading paths that lead to nowhere.

The entrance is marked 'S', and the exit is marked 'E':
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
x.........................................................xx
x........xxxx.xxx...xxxxxxxxxxxxxx........................xx
x.xxx....xxxx.xxx...xxxxxxxxxxxxx.........................xx
x.xxx....xxxx.xxx...xxxxxxxxxxxxxxxxxxxxxx.x.xxxxx.xxxxxx.xx
x.xxx.................................xxxx.x.xxxxx.xxxxxx.xx
x..............xx.x.xxxxxxxx.xxxxxxxx.xxxx.x.xxxxx.xxxxxx.xx
x.xx...x.xxxx.xxx.x.xxxxxxxx.xxxx..............xxx.xxxxxx.xx
x.xx.x.x.xxxx.xxx.x.xxxxxxxx.x............................xx
x.xx.x.x.xxxx.xxx.x.xxxxxxxx.x.xxxxx.xxxxxxx.x.xxx.xxxxx..xx
x.xxxx.x.xxxx.xxx......xxxxx.x.xxxxx.xxxxxxx.x.xxx.xxxxx..xx
x.xxx..................xxxxx.x.xxxxx.xxx...................E
S.xxxx.x.xxx..x.xx...x.xxxxx.x.xxxxx.xxxxxxx.x.xxx.xxxx.x.xx
xxxxxx.x.xxx..x.xx...x.xxxxx.x.xxxxx.xxxxxxx.xxxxx.xxxx.x.xx
xxxxxx.x.............x.xxxxx.x.xxxxx.xxxxxxx.xxxxx.xxxx.x.xx
xxxxxx.x.xxx..x.xxx..........x.xxxxxxxxxxxxx.xxxxx.xxxx.x.xx
xxxxxx...........xx.xx.xxxxx.x.xxxxxxxxxxxxx.xxxxx.xxxx.x.xx
xxxxxx.x...................x.x............xx.xxxxx.xx.....xx
x.xxxx.x.xxx.........................xxxxxxx.xxxxx.xxxx.x.xx
x..xxx.x.x......xxx.xxxxxxxx.x.xxxxxxxxxxxxx.xxxxx.xxxx.x.xx
x.................x.xxxxxxxx.x.xxxxxxxxxxxxx.......xxxx.x.xx
x...xx.x.x.x..xxx.x.xxxxxxxx.x.xxxxxxxxxxxxxxxxxxx.xxxx.x.xx
x.................................xxxxxxxxxxxxxxxx........xx
xxxxxx.....xxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxx........xx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

In this maze, an additional pass is used to try and remove some of
the large blocs of walls, for better or for worse:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
x.....................................................x.x.xx
x..x.x.x.x.x.x.x.x.x.x.x...x.x..x...x.x.x..xxx.x.xxx.x.xx..x
x.x.x...x.......x.x.x.x.xxx.x.xx.x.......x....x....x.xxxx..x
x.x..xxx.xxxxxx......x..........x.........x.......x......x.x
x.x..x.x.x.x.xx..xxxx.xxxxxxxxxx.x.xxxx.x..xxx.x.x.x.xxxx..x
x.x..xxx.xxxxxx..xxxx...........x.....x.x..x.x.x.x.x.x.xx..x
x.x..xxx.xx....x.................x.xxxx.x..xxx.x.x.x..x.x..x
x..x....x.xxxxx..xxxxxxxxxxxxxxxx...x.x.xx.x.x.x.x.x.xxxx..x
x.x..xxx.x.xx...x..........x.x.x.x.x.xx.xx.xxx.x.x.x.x.xx..x
x..x.........xxx.xxxxxxxxxx.x.x.x...x..........x.x.x.x.xx..x
x.x.x.xx....x.xxx.x.x.x.x.xx.x.x.x.x.xx.x.x....x.x.x.x.xx..x
S.x...xx.....xx.xx.x.x.x.x.xx.x.x...x.x..x.xx.x..x.x.x.xx..x
x.x.x.xx...........................x.xx..x.x...x.x.x.x.xx..x
x..x..xx..x....x......xx.x.x.xx.x.x.x.x..x.xx....x.x.x...x.x
x............xx.xxxxxxxxx.x.x.xx.x.x.xx..x.x.x.x.x.x.......x
x.xx..xx.x...xx.........xx.x.xx.x.x.x.x..x.xx.x.xx.x.x.xx..x
x.xx.x.xxx.xx.x.......x.x.x.xx.x.x.xxxx..x.xxxxxxx.xxxxxx..x
x.xx.xx.xx.x.x.xxxxxxx.xxx.xxx.xxxxx...x..x.......x.....x..x
x.xx.x.x.x.x.xx.x.x.xx.x.xx........x.xx..x.xxxxxxx.xxxxxx..x
x.xx.xx.xx.x...xxxxxxx.x.xxxxxxxxxxx.xx..x........x........x
x.xx.xxxxx..x.x.......x.x...........x..x.xx.xxxxxx.xxxxxx..x
x...x.....x..x.x.x.x.x.x.x.x.x.x.x.x.x..x..x...............E
x...........................................xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

However, the end result is not the sexiest maze you will ever see, it’s a quick and dirty solution, for a nicer and more precise maze, you might want to check out a smarter algorithm. You can check out the source at github.

Tags: ,

April 8, 2011 0

Saving DX11 shared resources

By dominic in C/C++, Direct3D 11

Using shared resources in Direct3D can be useful for a number of reasons. They are pretty useful when it comes to saving a texture to file, or more commonly, saving a screen capture of the running application.
Saving a texture to a file in Direct3D is very easy, there is a function that does it for you: D3DX11SaveTextureToFile. That’s pretty cool, let’s check out what parameters the function takes. As per the documentation, the function takes a pointer to the device context, a pointer to the texture you want to save and an image file format and file name. That sounds sweet, but there is one problem, if you take a look at the first parameter, it’s a pointer to the device’s immediate context, the same one that is being used for draw calls and stuff. That’s a bummer, because if you are trying to save a large texture or you are using a “complex” image file format, this can kill the frame rate because the D3DX11SaveTextureToFile hogs the device context and no rendering can be done until the function returns. Not cool.

The obvious way to fix this would be to move the texture saving code over to it’s own thread. While that works, we also need to create another device and device context so that we can use the secondary context to save the texture, letting the main context deal with the rendering without spending any time in the D3DX11SaveTextureToFile function.

Ok, so it looks like this time we are going to be able to save our big ass texture without destroying the frame rate in the process. Well not quite, because we can’t save a texture created by the main device, with out “secondary” device context. This is where shared resources kick in.
What we need to do is create a shared resource and a shared handle to that resource with our main device in order to open that shared resource in our worker thread, grab the texture and save it with our second device context.

Before we get into some code, a quick disclaimer: this is a kind of “works for me” scenario. I’ve been using this snippet for all of 24 hours, so it might crash/break/deadlock/explode under certain circumstances, I don’t know, try before you buy.

The code for this is actually pretty simple. In the main thread, use the D3D11_RESOURCE_MISC_SHARED MiscFlag in the texture description if you want to make the texture a shared resource.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// running in the main thread
HRESULT h = WaitForSingleObject(g_mutex, INFINITE);
if (h == WAIT_OBJECT_0)
{
    // g_hasFrame is shared with the worker
    // if we don't have a frame waiting to be saved
    if (!g_hasFrame)
    {
        // we can create a shared texture
        this->canShareFrame = true;
    }
}
ReleaseMutex(g_mutex);
 
if (this->canShareFrame)
{
    ID3D11Texture2D *backBuffer = 0;
    this->_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBuffer));
 
    D3D11_TEXTURE2D_DESC td;
    backBuffer->GetDesc(&td);
    // flags our resource as "shared"
    td.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
 
    this->_device->CreateTexture2D(&td, 0, &g_tex);
    this->_context->CopyResource(g_tex, backBuffer);
    IDXGIResource *dxgiResource = 0;
    g_tex->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void **>(&dxgiResource));
 
    // create our shared handle that will be used by the worker to get the shared texture
    dxgiResource->GetSharedHandle(&g_shaderHandle);
    dxgiResource->Release();
    backBuffer->Release();
    this->canShareFrame = false;
}
 
h = WaitForSingleObject(g_mutex, INFINITE);
if (h == WAIT_OBJECT_0)
{
    // let the worker know there is a texture to be saved
    if (!this->canShareFrame)
        g_hasFrame = true;
}
ReleaseMutex(g_mutex);

Now, the worker can get that texture from the shared handle, and save it to a file with the second device and device context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// in the worker thread
// device_2 and context_2 are the "secondary" device and context
bool imgSaved = false;
ID3D11Texture2D *texture = 0;
HRESULT h = WaitForSingleObject(g_mutex, INFINITE);
if (h == WAIT_OBJECT_0)
{
    // check to see if there is an image to save
    if (g_hasFrame)
        needsSaved = true;
}
ReleaseMutex(g_mutex);
 
if (needsSaved)
{
    // use the shared handle to open the texture
    device_2->OpenSharedResource(g_shaderHandle, __uuidof(ID3D11Texture2D), (LPVOID*)&texture);
    if (texture)
    {
        D3DX11SaveTextureToFile(context_2, texture, D3DX11_IFF_PNG, "image.png");
        texture->Release();
        needsSaved = false;
    }
}
 
h = WaitForSingleObject(g_mutex, INFINITE);
if (h == WAIT_OBJECT_0)
{
    // let the main thread know it can share a new texture
    if (!needsSaved)
        g_hasFrame = false;
}
ReleaseMutex(g_mutex);

Et voilĂ , you can now save big ass texture to files without slowing down the application.
A better way to do it, might be to share a texture every frame, and add it to a queue, and let the worker(s) save the textures from the queue. This would allow you to record what the application is rendering. Note that there will be an increase in memory consumption and that you might drop a frame or two from time to time.
Here again, using the queued approach works for me but might not be bullet proof. I might post the code for the queued version if I ever get the time to refactor it and make it look like it wasn’t coded by an epileptic monkey.

This is worth reading too.

Tags: , ,

April 5, 2011 3

Water shader

By dominic in C/C++, Direct3D 11, HLSL

First render of a water shader. I will be adding atmospheric scattering as well as nicer reflection/refraction.

HLSL water shader from signalsondisplay on Vimeo.

A few articles worth reading:
Fresnel equations.
Schlick’s approximation.

Tags: , ,

March 25, 2011 1

At last! Direct3D 11!

By dominic in C/C++, Direct3D 11, HLSL

After burning a 5 years old Radeon X1950 and having my hard drive with all my stuff die on me, I finally got some time off to sit down and play with Direct3D 11, for I am now the owner of a GTX 460. So after a nice full day of working “hard”, I have a very small Direct3D 11 framework set up. This is just a little personal project I am going to be working on, as I intend to add some more “cool” stuff to it.

There is not much for the moment, just the basics: primitives, easy texture loading/managing, easy to use lighting, lots of different input layouts, a few shaders for lighting and env mapping, and some stats and utils.
I also have aliasing… lots of it!

A couple renders with environment mapping, dynamic lighting, texturing and a sky box.

I’ve lost all my source code and movies but this will keep me busy.
Story of my life. peace out.

Tags: , ,

March 11, 2011 1

Metawhatever

By dominic in C/C++, HLSL

A 100 metaballs, metalights, or whatever you want to call them as a post-processing effect. Download HD video

Metaballs from signalsondisplay on Vimeo.

Here is what the pixel shader might look like, where attenuation parameters are:
constant: 1.0, linear: 0.007, quadratic: 0.0002.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
float4 PS( OutputVertex v ) : SV_TARGET
{
	float4 color = float4(0, 0, 0, 1);
 
	for (int i = 0; i < g_numLights; i++)
	{
		float4 pcolor = float4(0, 0, 0, 0);
		float4 dir = g_pos[i] - v.pos;
		float dist = length(dir);
		if (dist < 800.0f)
		{
			dir /= dist;
			pcolor = g_clr[i] * dot(dir, normal);
		}
		color += pcolor / dot(a, float3(1.0f, dist, dist * dist));
	}
	return color;
}

Tags: , , ,

March 7, 2011 0

Win32 Project with console

By dominic in C/C++

Writing stuff to the console is one of the most basic means of debugging we have when writing a program. Yet, when creating a native C++ windows program, anything you write to one of the IO streams just gets ignored. There is a simple way to use a console in Win32 app, here is how.
The first thing to do is call AllocConsole(), and AttachConsole() passing it the current pid (GetCurrentProcessId()).
All this does is allocate a new console and attaches it to the current application.

1
2
AllocConsole();
AttachConsole(GetCurrentProcessId());

That’s nice, but using std::cout at that point won’t send anything to the console we just created. What we need to do is replace the cin/cout/cerr stream buffers with the console’s buffer:

1
2
3
4
5
6
7
8
// first we need to backup the current stream buffer so that we can restore it later
std::streambuf *backup = std::cout.rdbuf();
 
// then we need to open the output stream associated with the console
std::ofstream console_out("CONOUT$");
 
// once we have the console buffer, we can set it as the std::cout stream buffer
std::cout.rdbuf(console_out.rdbuf());

This works just the same for std::cin and std::cerr.
Now, whatever you send to std::cin/out/err will be printed to the console.
Once you are done with the console you just need to call FreeConsole() to remove it, and remember to restore the original stream buffers associated with the cout/in/err.

1
2
console_out.close();
std::cout.rdbuf(backup);

The best way to use this code is to wrap it up in a class, because as you will have noticed, if we put this in a function the console_out ofstream would fall out of scope when the function returns, and we don’t want to use global variables to store our streams and buffers.
Here is a basic example of such a class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef __DBGCONSOLE_H__
# define __DBGCONSOLE_H__
 
#include <iostream>
#include <streambuf>
#include <fstream>
 
class DebugConsole
{
public:
	DebugConsole();
	~DebugConsole();
 
	void open();
	void close();
 
private:
	std::streambuf	*_cinbuf;
	std::streambuf	*_coutbuf;
	std::streambuf	*_cerrbuf;
	std::ifstream	_console_cin;
	std::ofstream	_console_cout;
	std::ofstream	_console_cerr;
};
 
#endif // __DBGCONSOLE_H__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <windows.h>
#include "DebugConsole.h"
 
DebugConsole::DebugConsole() :
	_cinbuf(0), _coutbuf(0), _cerrbuf(0)
{
}
 
DebugConsole::~DebugConsole() {}
 
void DebugConsole::open()
{
	AllocConsole();
	AttachConsole(GetCurrentProcessId());
	this->_cinbuf = std::cin.rdbuf();
	this->_console_cin.open("CONIN$");
	std::cin.rdbuf(this->_console_cin.rdbuf());
	this->_coutbuf = std::cout.rdbuf();
	this->_console_cout.open("CONOUT$");
	std::cout.rdbuf(this->_console_cout.rdbuf());
	this->_cerrbuf = std::cerr.rdbuf();
	this->_console_cerr.open("CONOUT$");
	std::cerr.rdbuf(this->_console_cerr.rdbuf());
}
 
void DebugConsole::close()
{
	this->_console_cout.close();
	std::cout.rdbuf(this->_coutbuf);
	this->_console_cin.close();
	std::cin.rdbuf(this->_cinbuf);
	this->_console_cerr.close();
	std::cerr.rdbuf(this->_cerrbuf);
	FreeConsole();
}

Nothing fancy, but useful.

Tags: ,

February 6, 2011 2

HLSL particles

By dominic in C/C++, HLSL

10 million particles moving around a center of gravity with some Perlin noise thrown into the mix. Everything is done on the GPU. Download HD video

Particle dust from signalsondisplay on Vimeo.

Tags: , ,