Jump to content

  • Log In with Google      Sign In   
  • Create Account

2d Game Creation

Small break, but back to work

Posted by , 02 March 2015 - - - - - - · 841 views
Alpha Blending
Small break, but back to work I took a break due to work being hectic and everyone seeming to get sick. I added alpha blending and I have working armatures and working on the keyframes to create animations.


It looks like something

Posted by , 22 October 2014 - - - - - - · 656 views
#vectorart
It looks like something I got rid of most of the slider bars now that I have working color picking and constant buffers. So I decided to try and draw something. I was going for the mysterious woman on the water in a row boat.
All the shapes now have visible, clickable, control points. I need to work a little bit more on correct mouse movement translations (you move left but the control moves right). But I was able to accomplish this. Next is armatures for actual animation.

10 22 14



Color Picking, Constant Buffers, and Shaders

Posted by , 20 October 2014 - - - - - - · 728 views

FINALLY!!! Constant buffer worked without errors. I guess I kept running into bad examples. Many were missing information. I simply wanted to do color picking and set a constant buffer for the color. So both the color picking and the constant buffer (to set the object/shape to a solid color to be referenced) were a pain.
So
R - What kinds of pick (gui, object/shape, control point)
G - index1 (example - object index)
B - index2 (example - shape index)

So I finally wrote directx functions that are similar to my opengl counterparts.


For now this is my constant buffer (the name is from the msdn example). Vector4f is my own (x, y, z, w).
The other is my PixelShader, to which is stored in a vector for multiple shaders.
struct VS_CONSTANT_BUFFER
{
Vector4f modifier;
};
struct PixelShader
{
ID3D11PixelShader* shader; 
ID3D11Buffer*   g_pConstantBuffer11;
Vector4f modifier;
};
This is my AddShader routine. I currently have both my pixel shader and vertex shader in the same file, but left it like this in case I change my mind. I just give the same file name for both pix and vert.
Vector2i Shaders::AddShader(ID3D11Device *dev, ID3D11DeviceContext *devcon, char* pix, char* vert)
{
cShade = -1;
//The Shaders.  cShade holds the index of current shader loaded. -1 means none.
pVS.resize(pVS.size() + 1);
pPS.resize(pPS.size() + 1);
pLayout.resize(pLayout.size() + 1);
ID3D10Blob *VS, *PS;
HRESULT HRV = D3DX11CompileFromFile(vert, 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
HRESULT HRP = D3DX11CompileFromFile(pix, 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);


//Create the shaders and give the pointers.  Vertex currently does not have extra parameters is just a std::vector<ID3D11VertexShader*>
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS[pVS.size() - 1]);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS[pPS.size() - 1].shader);


//Each time the shaders are set, the modifier will be set to this initial value
pPS[pPS.size() - 1].modifier.x = 1.0f;
pPS[pPS.size() - 1].modifier.y = 1.0f;
pPS[pPS.size() - 1].modifier.z = 1.0f;
pPS[pPS.size() - 1].modifier.w = 1.0f;
//modify is what will be sent to the constant buffer
modify.modifier = pPS[pPS.size() - 1].modifier;

//constant buffer setup section START
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.ByteWidth = sizeof(modify);
bd.Usage = D3D11_USAGE_DEFAULT;


HRESULT hr = dev->CreateBuffer(&bd, 0, &pPS[pPS.size() - 1].g_pConstantBuffer11);
if( !FAILED( hr ) )
devcon->VSSetConstantBuffers( 0, 1, &pPS[pPS.size() - 1].g_pConstantBuffer11 );
//constant buffer setup section END

D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0},
}; 
dev->CreateInputLayout(ied, 3, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout[pLayout.size() - 1]);


return Vector2i(pPS.size() -1, pVS.size() - 1);
}
This part of the code I saw so many different variations on. This one worked for me (finally).
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.ByteWidth = sizeof(modify);
bd.Usage = D3D11_USAGE_DEFAULT;


HRESULT hr = dev->CreateBuffer(&bd, 0, &pPS[pPS.size() - 1].g_pConstantBuffer11);
if( !FAILED( hr ) )
devcon->VSSetConstantBuffers( 0, 1, &pPS[pPS.size() - 1].g_pConstantBuffer11 );

I selected my shader for drawing here.
void Shaders::SetShader(ID3D11DeviceContext *devcon, int index)
{
if (cShade == index) return;
cShade = index;
devcon->VSSetShader(pVS[index], 0, 0);
devcon->PSSetShader(pPS[index].shader, 0, 0);
devcon->IASetInputLayout(pLayout[index]);
SetConstantBuffer(devcon, pPS[cShade].modifier);
}
This code is used after I select the shader for the current draw (or when the shader is first selected). This will update the constant buffer to a new value. I can use it for color picking and other fun stuff.
void Shaders::SetConstantBuffer(ID3D11DeviceContext *devcon, Vector4f aMod)
{
modify.modifier = aMod;
devcon->UpdateSubresource(pPS[cShade].g_pConstantBuffer11, 0, 0, &modify, 0, 0);
devcon->PSSetConstantBuffers(0, 1, &pPS[cShade].g_pConstantBuffer11);
}
And this is the shader for my ellipse
struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
    float2 uv : UV;
};
cbuffer VS_CONSTANT_BUFFER : register(b0)
{
    float4 modifier;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR, float2 uv : UV)
{
    VOut output;
    output.position = position;
    output.color = color;
    output.uv = uv;
    return output;
}


float4 PShader(float4 position : SV_POSITION, float4 color : COLOR, float2 uv : UV) : SV_TARGET
{
    float result = (uv.x * uv.x + uv.y * uv.y);
    if (color.a < 1.0) color = float4(.50, .50, .50, 1.0) * color;
    if (result > 1) discard; 

    if (modifier.w == 0.0)
    {
        color.r = modifier.x;
        color.g = modifier.y;
        color.b = modifier.z;
        color.a = 1.0;
    } 
    return color;
}

[Edit] Forgot Color Picking.
The Color format of the 1x1 texture must be the same as your backbuffer, or this is SO fail (took a while on that). The mouse must be in bounds or the srcbox will be said to be invalid.
Vector4f PickColor(int the2d, int x, int y, ID3D11Device *dev, ID3D11DeviceContext *devcon)
{
ID3D11Texture2D *BackBuffer;
HRESULT hr = swapchain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &BackBuffer ));

Vector4f a = Vector4f(0, 0, 0 ,0);

ID3D11Texture2D *Surface;
D3D11_TEXTURE2D_DESC StagedDesc = {
1,//Width;
1,//Height;
1,//MipLevels;
1,//ArraySize;
DXGI_FORMAT_R8G8B8A8_UNORM,//DXGI_FORMAT Format;
1, 0,//DXGI_SAMPLE_DESC SampleDesc;
D3D11_USAGE_STAGING,//D3D11_USAGE Usage;
0,//UINT BindFlags;
D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,//UINT CPUAccessFlags;
0//UINT MiscFlags;
};
dev->CreateTexture2D( &StagedDesc, NULL, &Surface);

D3D11_BOX srcBox;
srcBox.left = x;
srcBox.right = srcBox.left + 1;
srcBox.top = y;
srcBox.bottom = srcBox.top + 1;
srcBox.front = 0;
srcBox.back = 1;

devcon->CopySubresourceRegion(Surface, 0, 0, 0, 0, BackBuffer, 0, &srcBox);

D3D11_MAPPED_SUBRESOURCE msr;
if (devcon->Map(Surface, 0, D3D11_MAP_READ_WRITE, 0, &msr) != S_OK) return Vector4f(-1, -1, -1, -1);

void *pixelA = msr.pData;
std::vector<BYTE> pixel;

pixel.resize(4);
memcpy(&pixel[0], pixelA, 4);

a.x = (float)pixel[0];
a.y = (float)pixel[1];
a.z = (float)pixel[2];
a.w = (float)pixel[3];


pixel.resize(0);
devcon->Unmap(Surface, 0);
Surface->Release();
BackBuffer->Release();
return a;
}



Bezier, it's french

Posted by , 17 October 2014 - - - - - - · 537 views
#Bezier
Bezier, it's french So I got bezier curves kickin', along with variable width of the start, middle, and end. If you have not used bezier ([be.zje]) is actually not a hard concept, but very effective. They use control points to modify a line interpolation from straight line into a curve.
Coding Math 19 was very helpful.


I used cubic bezier, so I have a start point, end point, and two control points.


This is the code, to which I got directly from the video, but it is apparently just the code for quadratic bezier (1 control point) and Cubic bezier (2 control point). t is what percent along the line you are at (between 0.0f and 1.0f). You input the start, 1 or 2 control points depending, and the end point. You give the t and it will change pFinal to the correct point along the curve. The smaller the increments you give for t, the smoother the curve will look. All the curves in the picture are 20 segments.
void QuadraticBezier(Vector2f p0, Vector2f p1, Vector2f p2, float t, Vector2f& pFinal)
{
pFinal.x = powf(1.0f - t, 2.0f) * p0.x + (1 - t) * 2.0f * t * p1.x + t * t * p2.x;
pFinal.y = powf(1.0f - t, 2.0f) * p0.y + (1 - t) * 2.0f * t * p1.y + t * t * p2.y; 
}
void CubicBezier(Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3, float t, Vector2f& pFinal)
{
pFinal.x = powf(1.0f - t, 3.0f) * p0.x +
powf(1 - t, 2) * 3.0f * t * p1.x +
(1 - t) * 3 * t * t * p2.x + 
t * t * t * p3.x;
pFinal.y = powf(1.0f - t, 3.0f) * p0.y +
powf(1 - t, 2) * 3.0f * t * p1.y +
(1 - t) * 3 * t * t * p2.y + 
t * t * t * p3.y;
}
I also used a function I wrote called Wide. It uses the start, middle, and ending widths are parameters. t is the same as the curve. It calculates how wide the line will be. Before halfway through, it ignores the ending width. After halfway through, it ignores the beginning width. It was cleaner than having all this in the loop creating the curve.
Vector2f Wide(Vector2f a, Vector2f b, Vector2f c, float t)
{
float x, y;
if (t == 0.0f)
{
x = a.x;
y = a.y;
}
else if (t < .5f)
{
float d = t * 2.0f;
x = a.x * (1.0f - d) + b.x * d;
y = a.y * (1.0f - d) + b.y * d;
}
else if (t == .5f)
{
x = b.x;
y = b.y;
}
else
{
t = t - .5f;
float d = t * 2.0f;
x = b.x * (1.0f - d) + c.x * d;
y = b.y * (1.0f - d) + c.y * d;
}
return Vector2f (x, y);
}
10 17 14



Ellipses

Posted by , 12 October 2014 - - - - - - · 577 views
#directx
Ellipses Directx, What a pain in the butt! I learned opengl with no problems when it came to using uniform data and sending it to the shaders. Constant Buffers are not nearly as user friendly. I am sure they have wonderful attributes to them, but geez. But I did get my ellipses working along with my curved lines. I am using control points to define the length and width of both and then creating triangles that have u,v points to define the curves.


The Ellipse uvs
uv[0] = Vector2f(0.0f, 2.0f);
uv[1] = Vector2f(2.0f, 0.0f);
uv[2] = Vector2f(0.0f, 2.0f);
The uvs are 2.0 so a curve of 1 radius will touch the hypotenuse (longest side of a right triangle).
The vertices are added along with indices to form a diamond of triangles. The ellipse will be within the triangle.
objects[a].shapes[b].AddVertex(p[0],  col[2], uv[0]);
objects[a].shapes[b].AddVertex(p[1],  col[2], uv[1]);
objects[a].shapes[b].AddVertex(p[2],  col[2], uv[1]);
objects[a].shapes[b].AddVertex(p[3],  col[0], uv[2]);
objects[a].shapes[b].AddVertex(p[4],  col[2], uv[0]);




objects[a].shapes[b].AddTriangle(0, 3, 1);
objects[a].shapes[b].AddTriangle(0, 2, 3);


objects[a].shapes[b].AddTriangle(4, 1, 3);
objects[a].shapes[b].AddTriangle(4, 3, 2);
The pixel shader for ellipse

I am discarding any pixel that is greater than a length of 1. I am using the uvs to determine length.
float4 PShader(float4 position : SV_POSITION, float4 color : COLOR, float2 uv : UV) : SV_TARGET
{
float result = sqrt(uv.x * uv.x + uv.y * uv.y);
if (color.a < 1.0) color = float4(.50, .50, .50, 1.0) * color;
if (result > 1) discard;
    return color;
}
10 12 14



Win32

Posted by , 10 October 2014 - - - - - - · 352 views
#win32
Win32 Well I had super fun learning win32 without using a wrapper. I ended up with a system similar to what I used with my self made gui system, with the hWnd of each control being stored in an array. Now I have a drawing window, a working property page and a pop up (ish) window. Now I use sliders for adjust the properties so they can change on the fly.


Vector Graphics

Posted by , 07 October 2014 - - - - - - · 535 views
#vectorgraphics, c++, directx
So after figuring up the amount of work to make the bitmaps look fine on pc and android (all the different resolutions), I decided to go vector. So now I am making a vector graphics editor (aka like flash). This way it will scale to any resolution without loss.

10 07 14(sh)



Did not give up

Posted by , 01 October 2014 - - - - - - · 503 views
#Android
I kept flip flopping on what I wanted to do. It is hard for me to give up on trying to make a 3d game. And I also want to add a lot of material to a game, I love customization. So I decided to try and limit myself forcibly by doing this on Android. Most people are not going to have a gamepad with it, and on screen ones are hit and miss. So I am making sure I keep it simple enough to be effective with only a touchscreen.
In the last two weeks (in between work), I have make a tile-map editor and character animation editor.

My tile and character editor

Right now I don't have a screenshot of it actually working on android simply because I am re-writing the loading of the character right now. I switched from text based to binary, also added more information per frame of animation. The character is moving and collision detection is working (albeit with a couple of bugs). So far so good..


Raw Input API

Posted by , 05 December 2013 - - - - - - · 1,380 views

A lot of research went into using Raw Input API on a gamepad.
I am using a Logitech Dual Action usb gamepad.
This is where I got the best example. But he obviously changed part of the code cause it didn't work.
http://forums.tigsource.com/index.php?topic=15004.0

So after more research and tweeking, got it to work. Right now it is 4 buttons, two analog sticks, and the directional pad. The others wont be hard, just haven't done them yet.

you have to include HidClass.h
This may require installing the WDK (windows driver kit)
It may not as I believe Mingw already had it.
I tried a bunch of stuff so I installed WDK along the way.

This is in the windows WndProc
case WM_CREATE:
{
RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x05;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hWnd;

rid[1].usUsagePage = 0x01;
rid[1].usUsage = 0x04;
rid[1].dwFlags = RIDEV_INPUTSINK;
rid[1].hwndTarget = hWnd;

if (!RegisterRawInputDevices(rid, 2, sizeof(rid[0])))
{
PostQuitMessage(0);
return 0;
}
}
case WM_INPUT:
{
UINT cbSize;
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
GetRawInputData(hRawInput,RID_INPUT,0,&cbSize,sizeof(RAWINPUTHEADER));
LPBYTE lpbBuffer = new BYTE[cbSize];
GetRawInputData(hRawInput,RID_INPUT,lpbBuffer,&cbSize,sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpbBuffer;
if (lpbBuffer == NULL)
return 0;
if (raw->header.dwType == RIM_TYPEHID)
{
BYTE* test = new BYTE[raw->data.hid.dwCount * raw->data.hid.dwSizeHid];
test = &raw->data.hid.bRawData;

componentManager.gamepad.StateChange(0, test, raw->data.hid.dwCount * raw->data.hid.dwSizeHid);
}
return 0;
}


This is my gamepad class:
Each byte of data held multiple values. I am sure there is a better way of getting the values, but this worked.
I subtracted 127 from the analog so I could have a +/- value versus a 0 to 255.
I also made 16 the deadzone radius for the analog.
They stored 4 button values and the directional pad in one byte.
The value was 8 when nothing was pressed.
The directional pad was a value 0-7 when pressed.
Button 1: 16
Button 2: 32
Button 3: 64
Button 4: 128
I divided by 16 and made that Byte b.
BYTE c = data[5] - b * 16.

This made c the remainder due to rounding.
If no direction button is held, c would be negative because 8 would round up when divided by 16 due to the variable being a BYTE. So when multiplied by 16, it would be a number greater than data[5].
Otherwise, c would be 0-7.

void Gamepad::StateChange(int aPlayer, BYTE* data, int aSize)
{
if (player[aPlayer].type == 0)
{
player[aPlayer].analog[0].x = data[1] - 127;
player[aPlayer].analog[0].y = data[2] - 127;
player[aPlayer].analog[1].x = data[3] - 127;
player[aPlayer].analog[1].y = data[4] - 127;
if (player[aPlayer].analog[0].x < 17 && player[aPlayer].analog[0].x > -17) player[aPlayer].analog[0].x = 0;
if (player[aPlayer].analog[0].y < 17 && player[aPlayer].analog[0].y > -17) player[aPlayer].analog[0].y = 0;
if (player[aPlayer].analog[1].x < 17 && player[aPlayer].analog[1].x > -17) player[aPlayer].analog[1].x = 0;
if (player[aPlayer].analog[1].y < 17 && player[aPlayer].analog[1].y > -17) player[aPlayer].analog[1].y = 0;
bool a[4];
BYTE b = data[5] / 16;
BYTE c = data[5] - b * 16;
a[3] = (b >= 8);
if (a[3]) b -= 8;
a[2] = (b >= 4);
if (a[2]) b -= 4;
a[1] = (b >= 2);
if (a[1]) b -= 2;
a[0] = (b >= 1);
if (a[0]) b -= 1;
player[aPlayer].button[0] = a[0];
player[aPlayer].button[1] = a[1];
player[aPlayer].button[2] = a[2];
player[aPlayer].button[3] = a[3];
switch (c)
{
case(0):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = 1;
break;
case(1):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = 1;
break;
case(2):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = 0;
break;
case(3):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = -1;
break;
case(4):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = -1;
break;
case(5):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = -1;
break;
case(6):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = 0;
break;
case(7):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = 1;
break;
case(8):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = 0;
break;
}
}
}
void Gamepad::UpdateGamepad()
{
for (unsigned aPlayer = 0; aPlayer < 4; aPlayer++)
{

for (unsigned count = 0; count < 12; count++)
{
if (player[aPlayer].button[count] == true && player[aPlayer].prevButton[count] == false) player[aPlayer].buttonState[count] = 1; //just hit
else if (player[aPlayer].button[count] == true && player[aPlayer].prevButton[count] == true) player[aPlayer].buttonState[count] = 2; //held
else if (player[aPlayer].button[count] == false && player[aPlayer].prevButton[count] == true) player[aPlayer].buttonState[count] = 3; //just let go
else player[aPlayer].buttonState[count] = 0; //up
player[aPlayer].prevButton[count] = player[aPlayer].button[count];
}

}
}


After all the windows messaging is completed, UpdateGamepad() is called. This updates the button state by comparing it to the previous button state. Then all the previous button states are made equal to the current. This is done for all 4 potential players.


Small Break and now trying Gamepad support

Posted by , 26 November 2013 - - - - - - · 585 views

I worked some crazy hours the last few weeks and had a vacation. I spent the vacation catching up on shows and got the ps4, so was also playing that.
I'm working on getting the basics of the game going to I can sync both the animator and game together. I may implement something in the animator, and absolutely realize it was a terrible idea in the game. And vice versa.
Right now, I am trying to implement a gamepad.
MICROSOFT, what is your problem?
I found multiple links to XInput/DirectInput. It was like they found the worst programmer to write the example. There was poor structuring and goto.....I haven't seen a goto in years.
I said screw it, and am either going to use Raw Input API or maybe SDL.
I hear good things about SDL...just not sure if it is for me.






December 2016 »

S M T W T F S
    12 3
45678910
11121314151617
18192021222324
25262728293031

Recent Entries

Recent Comments