OMFG update

posted in Beals Software
Published April 24, 2006
Advertisement
Ethereal Darkness Interactive Update Yea, so I'm going to town working on the editor and I notice that the RichTextBox has a member named AutoWordSelection. So, I turn it on, comment out my code, and guess what? It already has the feature of double clicking and selecting a word =/ Oh well, now I now how to implement it into my textbox widget, so it wasn't a complete waste of time.

Now I'm working on implementing file comparison check, but I've run into some small problems. I've finally gotten it set up so that it doesn't keep asking over and over again (since I have the code in the Activated method), but now I keep getting IO exceptions. I type the text into the text editor, save it, switch to Notepad++, it asks if I want to reload and I say yes, I modify it and save, go back to the script editor, it asks if I want to reload, I say yes, and then I modify it and save. This is where I get the exception, it says that something else is accessing the file, when nothing has change (notepad++ is open the whole time.) I've double checked and I call Stream.Close() on all of my filestreams.


Dragonfire Games UpdateI've almost gotten the base class done. Its a large beast, but it holds a lot of functionality:
std::string	m_Text;POINT		m_Position;SIZE		m_Size;int			m_nType;POINT		m_ClientPosition;SIZE		m_ClientSize;bool		m_bEnabled;bool		m_bVisible;Widget*					m_pParent;std::vector	m_Children;std::vector	m_Selected;RECT	m_SrcRect;bool	m_bStretchRender;bool	m_bTabStop;int		m_nTabValue;int		m_nAlign;int		m_nDockType;std::string	m_CursorID;std::string	m_TextureID;public:	Widget()	{		m_pParent = 0;	}	virtual ~Widget()	{	}	POINT ScreenToClient(POINT ScreenPt)	{		POINT ClientPt;		ClientPt.x = ScreenPt.x - m_Position.x - m_ClientPosition.x;		ClientPt.y = ScreenPt.y - m_Position.y - m_ClientPosition.y;		return ClientPt;	}	POINT ClientToScreen(POINT ClientPt)	{		POINT ScreenPt;		ScreenPt.x = ClientPt.x + m_Position.x + m_ClientPosition.x;		ScreenPt.y = ClientPt.y + m_Position.y + m_ClientPosition.y;		return ScreenPt;	}	Widget* GetChildAt(POINT ClientPt)	{		for(std::vector::iterator Iter = m_Children.begin(); Iter != m_Children.end(); ++Iter)		{			Widget* pWidget = *Iter;		}	}	bool PointInClient(POINT ScreenPt)	{		return ((ScreenPt.x >= m_Position.x) && (ScreenPt.y >= m_Position.y) && (ScreenPt.x < (m_Position.x + m_Size.cx)) && (ScreenPt.y < (m_Position.y + m_Size.cy)));	}	virtual void OnCreate(WIDGETCREATEINFO* pInfo)	= 0;	virtual void OnDestroy()						= 0;	virtual void OnMove(int nX, int nY)				= 0;	virtual void OnResize(int nWidth, int nHeight)	= 0;	virtual void OnRender(GuiVertex* pVertices)		= 0;	virtual void OnLeftClick(MOUSEEVENTVALUES Event)		= 0;	virtual void OnLeftRelease(MOUSEEVENTVALUES Event)		= 0;	virtual void OnMiddleClick(MOUSEEVENTVALUES Event)		= 0;	virtual void OnMiddleRelease(MOUSEEVENTVALUES Event)	= 0;	virtual void OnRightClick(MOUSEEVENTVALUES Event)		= 0;	virtual void OnRightRelease(MOUSEEVENTVALUES Event)		= 0;	virtual void OnMouseMove(MOUSEEVENTVALUES Event)		= 0;	virtual void OnMouseWheel(MOUSEEVENTVALUES Event)		= 0;	virtual void OnKeyDown(KEYBOARDEVENTVALUES Event)		= 0;	virtual void OnKeyUp(KEYBOARDEVENTVALUES Event)			= 0;	virtual void OnChar(KEYBOARDEVENTVALUES Event)			= 0;	virtual void OnTextChanged()		= 0;	virtual void OnStateChanged()		= 0;	virtual void OnVisibilityChanged()	= 0;	virtual void OnSelectionChanged()	= 0;	std::string	GetText() const					{ return m_Text;			}	POINT		GetPosition() const				{ return m_Position;		}	SIZE		GetSize() const					{ return m_Size;			}	int			GetType() const					{ return m_nType;			}	POINT		GetClientPosition() const		{ return m_ClientPosition;	}	SIZE		GetClientSize() const			{ return m_ClientSize;		}	bool		IsEnabled() const				{ return m_bEnabled;		}	bool		IsVisible() const				{ return m_bVisible;		}	Widget*					GetParent() const	{ return m_pParent;			}	std::vector*	GetChildren()		{ return &m_Children;		}	std::vector*	GetSelected()		{ return &m_Selected;		}	RECT	GetSrcRect() const					{ return m_SrcRect;			}	bool	StretchRenderingOn() const			{ return m_bStretchRender;	}	bool	TabStopEnabled() const				{ return m_bTabStop;		}	int		GetTabValue() const					{ return m_nTabValue;		}	int		GetAlignment() const				{ return m_nAlign;			}	int		GetDockType() const					{ return m_nDockType;		}	std::string	GetCursorID() const				{ return m_CursorID;		}	std::string	GetTextureID() const			{ return m_TextureID;		}};

I'm going to remove the selected list, but I'm going to keep the selection methods (I'll just make them virtual.) This still isn't the final version.

As you can see, each widget can have a separate cursor and a separate texture. I'm going to have to change the system though, since the cursors will probably all be in the same file, plus I need to be able to specify animation (so I'll probably replace put in Quad versions of what I have now.)

Also, each widget can specify whether or not to use stretch mode. By default each widget requires 54 vertices (9 quads, 6 vertices per quad), whereas when in stretch mode a widget only requires 6 vertices. This method is simplified by my quad batch's subdivide method, wherein I call m_QuadBatch.Subdivide(0, 9) and it will divide node 0 (the only node in this case) into 9 different nodes (so a total 9 nodes all together.)

NOTE: I don't recommend using a QuadBatch type system for everything. The system is only supposed to be used in parts where a quad most likely will be split into multiple nodes (water, terrain, GUI, etc.)


DiscussionI wanted to discuss my QuadBatch system. The QuadBatch class contains a vector of quads and a pointer to a Direct3D device. It has several methods including Add(), AddRange(), Subdivide(), SubdivideEx().

The Add() and AddRange() methods are pretty straightforward. You supply Add() with a Quad pointer and it adds it to the vector. AddRange() has two versions, an array version and a vector version. The array version takes a pointer to an array, an integer to specify the start, and the number of nodes to add. The vector version takes a vector and two iterators, the start and end of the range.

The Subdivide() method is pretty straightforward as well. You supply which node and how many subnodes to create and it divides the node into N equal nodes. The original node is removed.

The SubdivideEx() method is a little more complicated. I haven't actually finished implementing the whole thing. It takes a node number and a pointer to a SUBDIVIDEEX structure. The SUBDIVIDEEX structure contains only 1 variable - a subdivide function. The point is that you're supposed to derive a class from SUBDIVIDEEX and then define your function. Here is an example:
// pseudocodeclass SUBDIVIDEBYSIZE : public SUBDIVIDEEX{public:	int Columns, Rows;	// SUBDIVIDE::protected Function - std::vector (*SUBDIVIDEEX_FUNCTION)(SUBDIVIDEEX* pData, int nNodeWidth, int nNodeHeight, Quad* pNode);};std::vector SubdivideBySize(SUBDIVIDEEX* pData, int nNodeWidth, int nNodeHeight, Quad* pNode){	SUBDIVIDEBYSIZE* pSizeData = (SUBDIVIDEBYSIZE*)pData;		int nNodeX		= pNode->GetPosition().x;	int nNodeY		= pNode->GetPosition().y;	int nNodeWidth	= pNode->GetWidth() / pSizeData->Columns;	int nNodeHeight	= pNode->GetHeight() / pSizeData->Rows;	std::vector NewVector;	NewVector.reserve(pSizeData->Columns * pSizeData->Rows);		Quad NewNode;	for(int nRow = 0; nRow < pSizeData->Rows; ++nRow)	{		for(int nCol = 0; nCol < pSizeData->Columns; ++nCol)		{			NewNode.Move(nNodeX, nNodeY);			NewNode.Resize(nNodeWidth, nNodeHeight);			NewVector.push_back(NewNode);			nNodeX += nNodeWidth;		}		nNodeX = pNode->GetPosition().x;		nNodeY += nNodeHeight;	}	return NewVector;}// Later onSUBDIVIDEBYSIZE SDBS;ZeroMemory(&SDBS, sizeof(SUBDIVIDEBYSIZE));SDBS.Columns	= 10;SDBS.Rows		= 10;SDBS.Function	= SubdivideBySize;MyQuadBatch.SubdivideEx(0, &SDBS);

No doubt there is a ton of errors in the above, but its pseudocode, so it doesn't really matter (you can point them out if you want.)
The SUBDIVIDEBYSIZE class would set its values to zero in its constructor (no need for the ZeroMemory() call) and it would set the function (since its not a public member and should never change.)

Anyway, in the example I take node 0 and split it into 100 different nodes, each WIDTH/10 and Height/10. So if node 0 was 100x100, each node would be 10x10. One problem with the example is that it uses integers, so if size division isn't perfect (like 101x101/10x10), the resulting quads will not cover the entire area. So, the final system will use floats.

Questions or comments?


RantOMFG NO RANT!!!
Previous Entry Update
Next Entry Can't sleep...
0 likes 1 comments

Comments

Programmer16
I just wanted to add that this system is in no way the fastest or most efficient. I chose it because it majorly simplifies many of the systems that I'm developing.
April 24, 2006 05:43 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement