• Advertisement
  • entries
  • comments
  • views

OMFG update

Sign in to follow this  


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 Update

I'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;
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.)


I 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:

// pseudocode
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)

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);
nNodeX += nNodeWidth;
nNodeX = pNode->GetPosition().x;
nNodeY += nNodeHeight;
return NewVector;

// Later on
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?


Sign in to follow this  

1 Comment

Recommended Comments

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.

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement