Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


cozzie

Member Since 13 Oct 2004
Offline Last Active Dec 24 2014 02:57 PM

#5198585 trying to avoid using if statements - is this good idea ?

Posted by cozzie on 16 December 2014 - 01:56 PM

Reading the original question, I think it shouldn't be a goal itself to get rid of if statements. I would say the goal is that your program delivers x, with y performance (and maybe keeping your code readable). If removing the if statement(s) visibly contributes to this goal, go for it. If it doesn't, it sounds like a waste of time (and possibly premature optimization).


#5198383 Do i have to make basic games again after break in gamedev?

Posted by cozzie on 15 December 2014 - 01:11 PM

I believe it all depends on what your goal is.
If you go indie, there's one choice: just do it.

If you're going for a job at a (AAA) studio, I'd suggest you come up with something that jumps of the page (not necessary on the looks of the output, can also be the way your code is setup or the algorithm you created etc.)

From your post I assume for now you're going indie, in that case you could set a goal (game) which includes both what you achieved earlier but with added features you want to learn.


#5198104 My Game Plan

Posted by cozzie on 14 December 2014 - 05:33 AM

Hi. Your plan sounds achievable if you ask me.
On the long term you might benefit (or not) from the language you choose. I'd prefer c++ because in the end I believe you have more control/ lower level. But when you're starting c# should be fine to start with. For both languages several API's/libraries are available for say rendering or math, so you dont have to do eveything yourself (right away).
Good luck


#5197888 Assets first?

Posted by cozzie on 12 December 2014 - 05:28 PM

As mentioned, there's a lot to gain in making (more importantly finishing) a few simple games first. Get out there and see how you like it. Because if you don't, then don't like multiplied by 100 is not something to look forward too.

I'm actually in a sort off similar situation, although I can code a bit (c++) instead of making art/ modelling. First I completely finished a 2d asteroids clone (with difficulty levels, multiple levels, leaderboard, even an end boss:)), then I've worked on an engine for years and now I'm on the path of finishing a 2nd game completely. In this case using my own engine. Achieving that is yet another step towards the COD competitor :)

Point is; how do you eat an elephant? Bit by bit.
Good luck


#5197048 Normals/ lighting in a bundled mesh versus separate meshes

Posted by cozzie on 08 December 2014 - 04:43 PM

Found it, it was a problem with my material settings (different materials with same texture, one was used for both).


#5196822 How to scale UI without losing image quality?

Posted by cozzie on 07 December 2014 - 01:39 PM

Depending on the number of resolutions you will support, you could straight forward make a hires texture for each resolution. Unless you're going for windowed in your final release (where users can resize the window freely), which I wouldn't advice to be honest. This will ask for quite some effort on a lot of other aspects too.


#5196683 Intros

Posted by cozzie on 06 December 2014 - 02:44 PM

Also an advice, don't let this stuff slow you down. You'll have time enough later (assuming your game isn't fully finished yet). Better invest in the game primarily


#5192495 What to do if a coding project starts to feel too complex to handle?

Posted by cozzie on 12 November 2014 - 02:35 PM

Next time maybe spend more time on the design.

 
That's not always enough. It's quite rare that you know exactly what you're going to build when you set out to build a game. You might start out trying to build one thing, but find that it just isn't fun, so the requirements change the game into something else. Or the design just isn't workable because you didn't think of something, or the way you designed a particular component puts unnecessary restrictions on how other features of the game can access that component. Or maybe you have to redesign something because you didn't foresee where the performance bottlenecks would actually be, and end up putting in a whole bunch of complicated hacks to keep the program in your memory or speed requirements.
 
In any case, the longer you work on a program, the more complicated and unwieldy it is likely to get. This holds true regardless of how disciplined you are and this is why refactoring is important. In my view, refactoring (and knowing when and how to do it) is an important part of being a disciplined programmer.

I might be stubborn, but any project would benefit from having some sort of design thought out before running of to code. At least that's my opinion, unless it's just experimenting around a bit. Of course it doesn't have to 100% in detail and can change/ adapt to new insights.


#5192096 What to do if a coding project starts to feel too complex to handle?

Posted by cozzie on 10 November 2014 - 11:38 AM

Next time maybe spend more time on the design.
And what also works for me is having a class for everything, don't mix things too much. Same for namespaces keeping classes grouped. Like renderer, audio, ui, io, etc.

I also try to maintain discipline is function and member naming.

There's obviously no right answer, but this can help.


#5178892 Request for Explanation of Light Half Vector ...

Posted by cozzie on 08 September 2014 - 11:12 AM

This one helped me for sure:
https://m.youtube.com/watch?v=hmKgNjQLm3A&list=PLW3Zl3wyJwWOpdhYedlD-yCB7WQoHf-My


#5177923 V-sync and crispy textures

Posted by cozzie on 03 September 2014 - 02:41 PM

Update: I found it, after resetting the device, I wasnt't 'resetting'/initializing my state machine.

So all d3d states (render, texture, sampler) were los and not recovered, all good now (probably texture filtering).

Thanks again for helping me in the right direction.




#5177512 Moving from dinput to RAW input (mouse)

Posted by cozzie on 01 September 2014 - 03:44 PM

Hi guys.

I've made up my mind and finished my new input manager:

 

- keyboard handling through Windows messages

- mouse input using RAW input

 

Timing works fine to, same response/ speeds with and without V-sync.

I've pasted the code below, really like to hear your thoughts.

// Winproc

		// HANDLE KEYBOARD INPUT SOURCE DATA
		case WM_KEYDOWN:
			_input.SetKeyState(wParam, true);

			if(_input.KeyPressed(VK_ESCAPE))				// PRESSED
			{ 
				active = false; 
				PostMessage(_d3d.GetHwnd(), WM_QUIT, 0, 0);
			}
			break;

		case WM_KEYUP:
			_input.SetKeyState(wParam, false);
			break;

		// RAW INPUT: MOUSE
		case WM_INPUT:
		{
			UINT bufferSize;
			GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER));
			GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)_input.GetMouseBufferPtr(), &bufferSize, sizeof(RAWINPUTHEADER));

			_input.UpdateMouseRaw();
		}
		break;

// per frame handling input logistics

	if(_input.IsInitialized())
	{
		// KEYBOARD INPUT: turn on/off v-sync
		if(_input.KeyPressed(VK_F4))																			// PRESSED
		{
			if(!_d3d.mSettings.GetVsync()) _d3d.SetVsync(true);
			else _d3d.SetVsync(false);
		}
		
		float currInt = _d3dscene.mLights[1].GetIntensity();

		if(_input.KeyDown(VK_UP))	_d3dscene.mLights[1].SetIntensity(currInt += 0.05f);						// DOWN
		if(_input.KeyDown(VK_DOWN))	_d3dscene.mLights[1].SetIntensity(currInt -= 0.05f);						// DOWN

// etc etc

		if(!_d3dscene.IsAnimated())
		{
			if(_input.MouseMoved()) _d3dcam.FreeLook(_input.GetMouseMoveX(), _input.GetMouseMoveY(), _player.GetLookSpeed());
		
			if(_input.MouseButtonPressed(0))
			{
				_audio.PlaySceneFx(_player.GetCurrentWeapon(), false);

				CheckBulletCollision();
			}

// etc etc

// the input class interface

class CInputHandler
{
public:
	//	KEYBOARD: WINDOWS MESSAGING
	bool KeyPressed(const int pKey)				const;
	bool KeyDown(const int pKey)				const;

	//	MOUSE: RAW INPUT
	int GetMouseMoveX()							const;
	int GetMouseMoveY()							const;
	bool MouseMoved()							const;

	bool MouseButtonDown(const int pButton)		const;
	bool MouseButtonPressed(const int pButton)	const;

	bool MouseScrolled()						const;
	int GetMouseScrollPos()						const;

	//	OTHER
	bool IsInitialized()						const;

	void UpdateKeys();
	void SetKeyState(const int pKey, const bool pState);

	bool SetupMouseRaw(const HWND pHwnd);
	void UpdateMouseRaw();

	BYTE* GetMouseBufferPtr();

	void Reset();

	CInputHandler();
	~CInputHandler();

private:
	// KEYBOARD: WINDOWS MESSAGING
	bool			mKeys[256];
	bool			mLastKeys[256];

	// MOUSE: RAW INPUT
	RAWINPUT*		mRawInput;
	RAWINPUTDEVICE	Rid[1];

	BYTE			*mMouseBuffer;
	
	int				mMouseMoveX, mMouseMoveY;
	bool			mMouseMoved;

	bool			mMouseButtonDown[3];
	bool			mLastMouseButtonDown[3];

	bool			mMouseScrolled;
	int				mMouseScrollPos;
	int				mMouseLastScrollPos;

	// OTHER
	bool			mInitialized;
};

// input handler class implementation

CInputHandler::CInputHandler()
{
	mRawInput			= NULL;
	mMouseBuffer		= NULL;
	
	mMouseMoved			= false;
	mMouseScrolled		= false;

	mMouseMoveX			= 0;		
	mMouseMoveY			= 0;

	mMouseScrollPos		= 0;
	mMouseLastScrollPos	= 0;

	mInitialized		= false;
}

/**************************************************************************************/
/***								DESTRUCTOR										***/
/*** ==> usage: when CInputHandler object is not needed anymore						***/
/*** ==> releases all input handler objects											***/
/**************************************************************************************/

CInputHandler::~CInputHandler()
{
	mRawInput = NULL;

	delete[] mMouseBuffer;
	// nothing
}


/**************************************************************************************/
/***								UPDATE KEYS										***/
/*** ==> usage: to copy the current keys state to last keys 						***/
/*** ==> memcpy's the whole keys array of bools										***/
/**************************************************************************************/

void CInputHandler::UpdateKeys()
{
	memcpy(mLastKeys, mKeys, sizeof(mKeys));
}

/**************************************************************************************/
/***								SET KEY STATE									***/
/*** ==> usage: to update the state of an individual key							***/
/*** ==> updates the state															***/
/**************************************************************************************/

void CInputHandler::SetKeyState(const int pKey, const bool pState)
{
	mLastKeys[pKey] = mKeys[pKey];
	mKeys[pKey] = pState;
}

/**************************************************************************************/
/***								SETUP MOUSE RAW									***/
/*** ==> usage: at initalization, if user input is needed							***/
/*** ==> sets up RAW input for mouse (no DX/Dinput)									***/
/**************************************************************************************/

bool CInputHandler::SetupMouseRaw(const HWND pHwnd)
{
	Rid[0].usUsagePage	= HID_USAGE_PAGE_GENERIC; 
    Rid[0].usUsage		= HID_USAGE_GENERIC_MOUSE; 
    Rid[0].dwFlags		= RIDEV_CAPTUREMOUSE | RIDEV_INPUTSINK | RIDEV_NOLEGACY;
    Rid[0].hwndTarget	= pHwnd;
	
	if(!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]))) return false;

	mMouseBuffer = new BYTE[40];

	mInitialized = true;
	return true;
}

/**************************************************************************************/
/***								UPDATE MOUSE RAW								***/
/*** ==> usage: during runtime, after WM_INPUT message is received					***/
/*** ==> updates mouse properties based on RAW mouse input							***/
/**************************************************************************************/

void CInputHandler::UpdateMouseRaw()
{
	mRawInput = NULL;
	mRawInput = (RAWINPUT*)mMouseBuffer;

	if(mRawInput != NULL)
	{
		if(mRawInput->header.dwType == RIM_TYPEMOUSE)
		{
			mMouseScrolled = false;
		
			// POSITION
			mMouseMoveX += mRawInput->data.mouse.lLastX;
			mMouseMoveY += mRawInput->data.mouse.lLastY;
			mMouseMoved = true;

			// BUTTONS
			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN)
			{
				mLastMouseButtonDown[0] = mMouseButtonDown[0];
				mMouseButtonDown[0] = true;
			}
			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_UP)
			{
				mLastMouseButtonDown[0] = mMouseButtonDown[0];
				mMouseButtonDown[0] = false;
			}

			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_MIDDLE_BUTTON_DOWN)
			{
				mLastMouseButtonDown[1] = mMouseButtonDown[1];
				mMouseButtonDown[1] = true;
			}
			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_MIDDLE_BUTTON_UP)
			{
				mLastMouseButtonDown[1] = mMouseButtonDown[1];
				mMouseButtonDown[1] = false;
			}

			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_RIGHT_BUTTON_DOWN)
			{
				mLastMouseButtonDown[2] = mMouseButtonDown[2];
				mMouseButtonDown[2] = true;
			}
			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_RIGHT_BUTTON_UP)
			{
				mLastMouseButtonDown[2] = mMouseButtonDown[2];
				mMouseButtonDown[2] = false;
			}

			// SCROLL
			if(mRawInput->data.mouse.ulButtons & RI_MOUSE_WHEEL)
			{
				mMouseScrolled = true;

				mMouseLastScrollPos = mMouseScrollPos;
				if(mRawInput->data.mouse.usButtonData > 0) mMouseScrollPos = 1;
				else mMouseScrollPos = -1;
			}	
		}
	}
}

/**************************************************************************************/
/***							GET MOUSE BUFFER PTR								***/
/*** ==> usage: when RAW input needs updating in the wndproc						***/
/*** ==> returns a pointer to the BYTE buffer										***/
/**************************************************************************************/

BYTE* CInputHandler::GetMouseBufferPtr()
{
	return mMouseBuffer;
}

/**************************************************************************************/
/***									RESET										***/
/*** ==> usage: during runtime, after input logics are handled						***/
/*** ==> resets all (mouse) properties for new WM_INPUT input (frame timing)		***/
/**************************************************************************************/

void CInputHandler::Reset()
{
	mMouseMoved = false;
	mMouseScrolled = false;

	mMouseButtonDown[0] = false;
	mMouseButtonDown[1] = false;
	mMouseButtonDown[2] = false;

	mMouseMoveX = 0;
	mMouseMoveY = 0;
}


/**************************************************************************************/
/***									KEY PRESSED							  CONST	***/
/*** ==> usage: when checking specific keyboard input								***/
/*** ==> returns true if the key was not down in last frame + is down now			***/
/**************************************************************************************/

bool CInputHandler::KeyPressed(const int pKey) const
{
	return (!mLastKeys[pKey] && mKeys[pKey]);
}

/**************************************************************************************/
/***									KEY DOWN							  CONST	***/
/*** ==> usage: when checking specific keyboard input								***/
/*** ==> returns true if the key is down, based on current key state				***/
/**************************************************************************************/

bool CInputHandler::KeyDown(const int pKey) const
{
	return mKeys[pKey];
}

/**************************************************************************************/
/***							GET	MOUSE MOVE X							  CONST	***/
/*** ==> usage: to retrieve mouse X movement , from outside class					***/
/*** ==> returns the last mouse movement on the X-axis								***/
/**************************************************************************************/

int CInputHandler::GetMouseMoveX() const
{
	return mMouseMoveX;
}

/**************************************************************************************/
/***							GET	MOUSE MOVE Y							  CONST	***/
/*** ==> usage: to retrieve mouse Y movement , from outside class					***/
/*** ==> returns the last mouse movement on the Y-axis								***/
/**************************************************************************************/

int CInputHandler::GetMouseMoveY() const
{
	return mMouseMoveY;
}

/**************************************************************************************/
/***								MOUSE MOVED								  CONST	***/
/*** ==> usage: when checking if mouse has moved, outside class						***/
/*** ==> returns true if the mouse has moved										***/
/**************************************************************************************/

bool CInputHandler::MouseMoved() const
{
	return mMouseMoved;
}

/**************************************************************************************/
/***							MOUSE BUTTON DOWN							  CONST	***/
/*** ==> usage: to check if a specific mouse button is down, from outside class		***/
/*** ==> returns the current status of the mouse button								***/
/**************************************************************************************/

bool CInputHandler::MouseButtonDown(const int pButton) const
{
	return mMouseButtonDown[pButton];
}

/**************************************************************************************/
/***							MOUSE BUTTON PRESSED						  CONST	***/
/*** ==> usage: to check if a specific mouse button was pressed						***/
/*** ==> returns if the button was pressed											***/
/**************************************************************************************/

bool CInputHandler::MouseButtonPressed(const int pButton) const
{
	if(!mLastMouseButtonDown[pButton] && mMouseButtonDown[pButton]) return true;
	return false;
}

/**************************************************************************************/
/***								MOUSE SCROLLED							  CONST	***/
/*** ==> usage: when checking if the was scrolled, outside class					***/
/*** ==> returns true if the mouse has scrolled										***/
/**************************************************************************************/

bool CInputHandler::MouseScrolled()	const
{
	return mMouseScrolled;
}

/**************************************************************************************/
/***							GET MOUSE SCROLLPOS							  CONST	***/
/*** ==> usage: to retrieve the current scroll position of the mouse 				***/
/*** ==> returns the current position												***/
/**************************************************************************************/

int CInputHandler::GetMouseScrollPos() const
{
	return mMouseScrollPos;
}

/**************************************************************************************/
/***								IS INITIALIZED							  CONST	***/
/*** ==> usage: when wanting to know if directinput is initialized					***/
/*** ==> returns true if the dinput devices are ready to go							***/
/**************************************************************************************/

bool CInputHandler::IsInitialized() const
{
	return mInitialized;
}

}




#5173966 Sorting out the bits

Posted by cozzie on 15 August 2014 - 01:24 PM

Thanks, I switched dist and inst, because I first want to sort on dist (distance from camera).

For now:

		makeKey |= (UINT64)tr.MatGroup		<< 60;
		makeKey |= (UINT64)tr.Material		<< 52;
		makeKey |= (UINT64)tr.Mesh			<< 44;
		makeKey |= (UINT64)tr.DistToCamSqr	<< 28;
		makeKey |= (UINT64)tr.Instance;

Results:

ID	matgrp	matl	mesh	inst	distsqr
2	0	0	7	1523.69	44
1	0	0	7	1928.28	44
0	0	0	7	2679.06	44
1	0	0	8	1526.07	45
2	0	0	8	1961.64	45
0	0	0	8	2678.64	45
5	0	1	1	641.774	30
0	0	1	1	863.876	30
1	0	2	1	297.844	28
7	0	2	1	298.979	28
3	0	2	1	302.922	28
3	0	2	1	681.976	30
7	0	2	1	710.025	30
1	0	2	1	715.996	30
2	0	3	1	324.312	28
2	0	3	1	784.915	30
0	0	9	13	26.7233	14
0	0	9	13	26.5313	16
0	0	9	13	50.9233	15
0	0	9	13	50.7313	17
1	0	10	13	31.211	14
1	0	10	13	31.019	16
1	0	10	13	56.941	15
1	0	10	13	56.749	17
2	0	11	13	26.546	14
2	0	11	13	27.884	16
2	0	11	13	50.746	15
2	0	11	13	52.084	17
3	0	12	13	23.4845	14
3	0	12	13	23.2925	16
3	0	12	13	45.9625	17
3	0	12	13	46.1545	15
4	0	13	13	26.4275	16
4	0	13	13	28.1495	14
4	0	13	13	50.6275	17
4	0	13	13	52.3495	15
0	0	19	17	632.05	10
1	0	24	21	241.486	3
0	0	24	21	244.611	3
2	0	25	21	257.666	3
0	1	14	14	0	1
0	1	14	14	24.6981	12
1	1	15	14	0	1
1	1	15	14	25.8981	12
2	1	16	14	0	1
2	1	16	14	25.8144	12
19	1	21	19	210.195	5
4	1	21	19	219.088	5
3	1	21	19	220.368	5
12	1	21	19	237.035	5
5	1	21	19	240.494	5
9	1	21	19	242.705	5
17	1	21	19	248.869	5
1	1	21	19	251.263	5
18	1	21	19	266.779	5
16	1	21	19	274.828	5
2	1	21	19	274.758	5
0	1	21	19	279.369	5
20	1	21	19	281.241	5
23	1	21	19	286.909	5
21	1	21	19	289.241	5
22	1	21	19	296.312	5
25	1	21	19	299.007	5
24	1	21	19	301.771	5
11	1	21	19	313.179	5
15	1	21	19	316.496	5
7	1	21	19	325.97	5
6	1	21	19	327.245	5
9	1	21	19	333.87	6
5	1	21	19	339.316	6
8	1	21	19	347.619	5
16	1	21	19	348.235	6
10	1	21	19	349.88	5
2	1	21	19	352.877	6
14	1	21	19	357.944	5
19	1	21	19	361.184	6
13	1	21	19	371.248	5
12	1	21	19	371.141	6
18	1	21	19	391.29	6
0	1	21	19	399.231	6
10	1	21	19	399.653	6
20	1	21	19	401.6	6
23	1	21	19	401.844	6
8	1	21	19	405.05	6
3	1	21	19	406.877	6
21	1	21	19	408.107	6
4	1	21	19	413.153	6
22	1	21	19	413.031	6
25	1	21	19	414.707	6
24	1	21	19	415.278	6
11	1	21	19	423.048	6
15	1	21	19	424.459	6
1	1	21	19	431.338	6
17	1	21	19	434.9	6
13	1	21	19	439.107	6
6	1	21	19	472.361	6
14	1	21	19	478.828	6
7	1	21	19	478.642	6
8	1	35	25	319.827	54
4	2	4	1	307.071	28
6	2	4	1	307.903	28
6	2	4	1	691.557	30
4	2	4	1	692.514	30
3	2	7	4	648.601	18
0	2	7	4	731.78	18
2	2	7	4	807.783	24
5	2	7	4	852.965	18
4	2	7	4	977.865	18
4	2	7	4	1048.26	24
5	2	7	4	1195.96	24
1	2	27	22	25.9537	2
0	3	6	3	458.656	39
0	3	6	3	505.257	40
0	3	6	3	541.335	41
0	3	8	9	660.565	46
0	3	8	10	698.492	47
0	3	8	11	160.596	48
0	3	8	12	131.051	49
0	3	17	15	0	0
1	3	17	15	0	0
2	3	17	15	0	0
1	3	17	15	48.7949	13
0	3	17	15	50.8262	13
2	3	17	15	51.9707	13
0	3	22	20	804.828	4
1	3	23	20	879.321	4
0	3	26	22	25.941	2
2	3	30	25	321.517	54
0	3	30	25	323.753	54
1	3	30	25	323.794	54
3	3	31	25	328	54
4	3	32	25	322.811	54
5	3	32	25	323.494	54
6	3	33	25	321.439	54
10	3	33	25	321.502	54
7	3	34	25	320.425	54
9	3	36	25	320.352	54




#5172908 EffectEd - an HLSL editor

Posted by cozzie on 11 August 2014 - 02:58 PM

Great tool, thanks!

Any improvements planned?




#5172091 Sorting a bucket

Posted by cozzie on 07 August 2014 - 12:31 PM

Hi all,

 

I have a few questions on how to sort my renderbucket (in my renderqueue).

Below you can find an example of the current content in my opaqua render bucket.

 

The struct that I use per renderable is this:

typedef struct Q_RENDERABLE			// renderable level; for filling render buckets
{
	int	MatGroup;
	int	Material;
	int	Mesh;
	int	Instance;
	int	Id;		
	bool Visible;
	float DistToCamSqr;
} Q_RENDERABLE;

My questions:

- what would you advice on another way of sorting, I know fully based it on materialgroup (shader), mesh, instance etc., to reduce state changes, texture changes, shader changes etc. All works pretty good, but I don't do anything yet with distance to camera (front to back might be useful for early-z, but how to combine both sorting options?)

- say I insert or add renderables (for new entities), how can I easily sort them based on one of the variables, with std::sort or something?

(I have a std::vector<int> where I can simply store the indices of the renderables in a specific order)

- could I maybe create some sort of key based on the 7 variables and sort that?

 

Any help is appreciated.

 

An example of the bucket, current sorting:

ID	matgrp	matl	mesh	inst	distsqr

0	0	0	7	44	2679.06
1	0	0	7	44	1928.28
2	0	0	7	44	1523.69
0	0	0	8	45	2678.64
1	0	0	8	45	1526.07
2	0	0	8	45	1961.64
0	0	1	1	30	863.876
5	0	1	1	30	641.774
1	0	2	1	28	297.844
3	0	2	1	28	302.922
7	0	2	1	28	298.979
1	0	2	1	30	715.996
3	0	2	1	30	681.976
7	0	2	1	30	710.025
2	0	3	1	28	324.312
2	0	3	1	30	784.915
0	0	9	13	14	26.7233
0	0	9	13	15	50.9233
0	0	9	13	16	26.5313
0	0	9	13	17	50.7313
1	0	10	13	14	31.211
1	0	10	13	15	56.941
1	0	10	13	16	31.019
1	0	10	13	17	56.749
2	0	11	13	14	26.546
2	0	11	13	15	50.746
2	0	11	13	16	27.884
2	0	11	13	17	52.084
3	0	12	13	14	23.4845
3	0	12	13	15	46.1545
3	0	12	13	16	23.2925
3	0	12	13	17	45.9625
4	0	13	13	14	28.1495
4	0	13	13	15	52.3495
4	0	13	13	16	26.4275
4	0	13	13	17	50.6275
0	0	19	17	10	632.05
0	0	24	21	3	244.611
1	0	24	21	3	241.486
2	0	25	21	3	257.666
0	1	14	14	1	0
0	1	14	14	12	24.6981
1	1	15	14	1	0
1	1	15	14	12	25.8981
2	1	16	14	1	0
2	1	16	14	12	25.8144
0	1	21	19	5	279.369
1	1	21	19	5	251.263
2	1	21	19	5	274.758
3	1	21	19	5	220.368
4	1	21	19	5	219.088
5	1	21	19	5	240.494
6	1	21	19	5	327.245
7	1	21	19	5	325.97
8	1	21	19	5	347.619
9	1	21	19	5	242.705
10	1	21	19	5	349.88
11	1	21	19	5	313.179
12	1	21	19	5	237.035
13	1	21	19	5	371.248
14	1	21	19	5	357.944
15	1	21	19	5	316.496
16	1	21	19	5	274.828
17	1	21	19	5	248.869
18	1	21	19	5	266.779
19	1	21	19	5	210.195
20	1	21	19	5	281.241
21	1	21	19	5	289.241
22	1	21	19	5	296.312
23	1	21	19	5	286.909
24	1	21	19	5	301.771
25	1	21	19	5	299.007
0	1	21	19	6	399.231
1	1	21	19	6	431.338
2	1	21	19	6	352.877
3	1	21	19	6	406.877
4	1	21	19	6	413.153
5	1	21	19	6	339.316
6	1	21	19	6	472.361
7	1	21	19	6	478.642
8	1	21	19	6	405.05
9	1	21	19	6	333.87
10	1	21	19	6	399.653
11	1	21	19	6	423.048
12	1	21	19	6	371.141
13	1	21	19	6	439.107
14	1	21	19	6	478.828
15	1	21	19	6	424.459
16	1	21	19	6	348.235
17	1	21	19	6	434.9
18	1	21	19	6	391.29
19	1	21	19	6	361.184
20	1	21	19	6	401.6
21	1	21	19	6	408.107
22	1	21	19	6	413.031
23	1	21	19	6	401.844
24	1	21	19	6	415.278
25	1	21	19	6	414.707
8	1	35	25	54	319.827
4	2	4	1	28	307.071
6	2	4	1	28	307.903
4	2	4	1	30	692.514
6	2	4	1	30	691.557
0	2	7	4	18	731.78
3	2	7	4	18	648.601
4	2	7	4	18	977.865
5	2	7	4	18	852.965
2	2	7	4	24	807.783
4	2	7	4	24	1048.26
5	2	7	4	24	1195.96
1	2	27	22	2	25.9537
0	3	6	3	39	458.656
0	3	6	3	40	505.257
0	3	6	3	41	541.335
0	3	8	9	46	660.565
0	3	8	10	47	698.492
0	3	8	11	48	160.596
0	3	8	12	49	131.051
0	3	17	15	0	0
1	3	17	15	0	0
2	3	17	15	0	0
0	3	17	15	13	50.8262
1	3	17	15	13	48.7949
2	3	17	15	13	51.9707
0	3	22	20	4	804.828
1	3	23	20	4	879.321
0	3	26	22	2	25.941
0	3	30	25	54	323.753
1	3	30	25	54	323.794
2	3	30	25	54	321.517
3	3	31	25	54	328
4	3	32	25	54	322.811
5	3	32	25	54	323.494
6	3	33	25	54	321.439
10	3	33	25	54	321.502
7	3	34	25	54	320.425
9	3	36	25	54	320.352






PARTNERS