markgame66

Members
  • Content count

    50
  • Joined

  • Last visited

Community Reputation

132 Neutral

About markgame66

  • Rank
    Member
  1. what would be used in games? I guess they'd have some similar concepts?
  2. Hi all, I've been thinking some more about updating the UI for my app. It makes use of a OpenGL component to visualize the map, but I want the app to look better. Currently the app is a dialog box (as I mentioned in a similar thread) with drop downs, data displays control buttons etc. How easy is this is do in OpenGL? I'd really like to make all the parts look much better than simple windows stuff. Are there any apps that you can design the UI in a similar way you would in visual studio, but for OpenGL, generating the code out the back end? Is this a completely bad way of going about this? Thanks for any advise Mark
  3. Yeah I was wondering about Qt. The backend is C++, but can easly write wrappers for C# and the like.
  4. Hi All, To start with I realise that this is a bit of a open ended question. I've been thinking of updating my MFC/OpenGL app to something a bit more up to date, and for no other reason to make it look more "tarty" :) As it stands at the moment, it's basically a MFC Dialoge app, covered with buttons, drop down selection boxes, data output boxes and an OpenGL window (For visulising a map). The real work is all in encapsulated in the engine so it should be really a case of jsut hooking it up to another UI front end. This time I have in mind some more full screen with the primary controls avaliable and menus that'll slide in for the other parts.... Just wondered if anyone had any suggestions for some tools that would make the job fairly hassle free - wife won't be overly impressed if I scoot off for ages learning something new ;) Thanks Mark
  5. Pathfinding questions

    Good starting point here for A* http://www.gamedev.net/reference/programming/features/astar/ To hug the ground you could increase the cost to move to a cell that was higher than the current one. Also there's some further reading on making the paths more natural. Mark
  6. cheers - I'll look into breaking is apart - see what happens :)
  7. A* for multiple units

    Hi nietger, Here's my code for a binary heap for A*. You'll need to change the data type it stores to what ever your using (Just done for my own purposes). There are a few hazzards are the moment like the sizing of the HeapStructure is static. I need to make the dynamic at some point. Key things to note are: m_CellsInList is just a hash table (I'm in the middle of messing around with that code at the moment) The main driver for the code is the m_FScore member var, which will determine the position of the object in the heap. Hope this is of some help Mark BinaryHeap.h struct HeapStructure { GridCell* MapElement; // The type of data stored in the heap long HeapPosition; // This is used to determine where in the heap and oject exists, and if/when it is updated this value is used to help // reposition it in calles to updateHeap() }; class BinaryHeap { public: BinaryHeap() { m_MAX_ELEMENTS = 100000; m_ElementsInList = 0; p_mBinaryHeap = new HeapStructure*[m_MAX_ELEMENTS]; } ~BinaryHeap() { m_CellsInList.RemoveAll(); for (long LoopCtr = 0; LoopCtr < m_ElementsInList; LoopCtr++) { delete p_mBinaryHeap[LoopCtr]->MapElement; delete p_mBinaryHeap[LoopCtr]; } delete[] p_mBinaryHeap; } int m_MAX_ELEMENTS; int left(int root) const; int right(int root) const; int parent(int child) const; void insertElement(GridCell* DataElement); GridCell* removeMin(); // Removes and returns the minimum object from the heap and reheaps the set void reHeap(int root); // Reheaps the heap from the root downwards int count() const; void clearHeap(); // Clears out the heap bool checkElementExists(GridCell* DataElement, long *FScore); const GridCell* getMin(); // Returns the minimum object from the heap, the heap is left unaffected bool checkHeapValidity(); // Checks that the heap is valid. Ensures that no element is less than the root and the element positions are correct void updateHeap(int child); // This will update the heap from a child, bubbling upwards to the root in the case of an in heap update private: HeapStructure** p_mBinaryHeap; // The data structure of the heap itself, it holds pointers to HeapStructure objects C3DHashtable<HeapStructure*> m_CellsInList; // Hash table used to determine whether an object is already in the heap long m_ElementsInList; // Number of elements in the heap }; BinaryHeap.cpp // Binary Heap implemetation to improve the A* Path finding algrothim's performance for Open and Closed list maintaiance. #include "BinaryHeap.h" #include <vector> using namespace std; int BinaryHeap::left(int root) const { return (root * 2) + 1; } int BinaryHeap::right(int root) const { return (root * 2) + 2; } // Calculates the position of a parent of a child int BinaryHeap::parent(int child) const { return (child - 1) / 2; } // Determines if an element exists in the heap bool BinaryHeap::checkElementExists(GridCell* DataElement, long *FScore) { HeapStructure* lExistingHeapRecordDataItem = NULL; if (m_CellsInList.Exists(static_cast<int>(DataElement->m_X), static_cast<int>(DataElement->m_Y), 0) == true) { lExistingHeapRecordDataItem = m_CellsInList.Retrieve(static_cast<int>(DataElement->m_X), static_cast<int>(DataElement->m_Y), 0); *FScore = lExistingHeapRecordDataItem->MapElement->m_FScore; return true; } return false; } // This method will either insert a new element into the heap, or if it finds that the element already exists then it will update // that element and maintain the heap to ensure is the properties are still correct. // It updates both the actual heap and the m_CellsInList, which is just a hash dictionary to record the position and existance of // elements in the heap void BinaryHeap::insertElement(GridCell* DataElement) { int new_pos; HeapStructure* lHeapRecordDataItem = NULL; HeapStructure* lExistingHeapRecordDataItem = NULL; if (DataElement->m_X == 6 && DataElement->m_Y == -3) { printf("Test Element %d", DataElement->m_FScore); } if (m_ElementsInList+1 >= m_MAX_ELEMENTS) { printf("Max Array Error %d", m_MAX_ELEMENTS); } lExistingHeapRecordDataItem = m_CellsInList.Retrieve(static_cast<int>(DataElement->m_X), static_cast<int>(DataElement->m_Y), 0); if (lExistingHeapRecordDataItem == NULL) { if (m_ElementsInList == 0) { lHeapRecordDataItem = new HeapStructure; lHeapRecordDataItem->MapElement = new GridCell(static_cast<long>(DataElement->m_X), static_cast<long>(DataElement->m_Y), DataElement->m_FScore); p_mBinaryHeap[m_ElementsInList] = lHeapRecordDataItem; lHeapRecordDataItem->HeapPosition = m_ElementsInList; m_ElementsInList++; } else { lHeapRecordDataItem = new HeapStructure; lHeapRecordDataItem->MapElement = new GridCell(static_cast<long>(DataElement->m_X), static_cast<long>(DataElement->m_Y), DataElement->m_FScore); p_mBinaryHeap[m_ElementsInList] = lHeapRecordDataItem; lHeapRecordDataItem->HeapPosition = m_ElementsInList; new_pos = m_ElementsInList; m_ElementsInList++; while((new_pos != 0) && (p_mBinaryHeap[new_pos]->MapElement->m_FScore <= p_mBinaryHeap[parent(new_pos)]->MapElement->m_FScore)) //loop while the item has not become the main root, and while its value is less than its parent { swap(p_mBinaryHeap[new_pos], p_mBinaryHeap[parent(new_pos)]); //swap the value of item with its lesser parent p_mBinaryHeap[new_pos]->HeapPosition = new_pos; p_mBinaryHeap[parent(new_pos)]->HeapPosition = parent(new_pos); new_pos = parent(new_pos); //update the item's positions } p_mBinaryHeap[new_pos]->HeapPosition = new_pos; p_mBinaryHeap[parent(new_pos)]->HeapPosition = parent(new_pos); } m_CellsInList.Insert(static_cast<int>(lHeapRecordDataItem->MapElement->m_X), static_cast<int>(lHeapRecordDataItem->MapElement->m_Y), 0, lHeapRecordDataItem); } else { // We're inserting a cell that already exists - in this case we need to re-heap to ensure the heap's // properly is maintained. long lTestFScore; bool lElementExists = checkElementExists(DataElement, &lTestFScore); if (lElementExists == true) { lExistingHeapRecordDataItem = NULL; lExistingHeapRecordDataItem = m_CellsInList.Retrieve(static_cast<int>(DataElement->m_X), static_cast<int>(DataElement->m_Y), 0); if ( lExistingHeapRecordDataItem != NULL) { // Update the F Score of the Map Element in the search list. This will then be resorted by the call to reHeap() if it is any better then before //if (lExistingHeapRecordDataItem->MapElement->m_FScore != DataElement->m_FScore) { printf("F Score Change Found"); lExistingHeapRecordDataItem->MapElement->m_FScore = DataElement->m_FScore; if ( p_mBinaryHeap[lExistingHeapRecordDataItem->HeapPosition]->MapElement->m_FScore < p_mBinaryHeap[parent(lExistingHeapRecordDataItem->HeapPosition)]->MapElement->m_FScore ) { swap(p_mBinaryHeap[parent(lExistingHeapRecordDataItem->HeapPosition)], p_mBinaryHeap[lExistingHeapRecordDataItem->HeapPosition]); p_mBinaryHeap[lExistingHeapRecordDataItem->HeapPosition]->HeapPosition = lExistingHeapRecordDataItem->HeapPosition; p_mBinaryHeap[parent(lExistingHeapRecordDataItem->HeapPosition)]->HeapPosition = parent(lExistingHeapRecordDataItem->HeapPosition); // Perform Heap Maintainance to correct the heap following an items update. updateHeap(lExistingHeapRecordDataItem->HeapPosition); } } } else { // Not good - we think we have a record of an element, but it wasn't found! printf("Null Pointer Error on existing element!"); } } else { printf("Element Does Not Exist, Error!"); } } } // The purpose of this method is to determine if the heap is valid. There are two things that are checked: // // 1. That for ever item in the heap it is less than the root element [0] // 2. That the recorded position of an element is the heap is correct and corresponds to the array position // ONLY USE FOR DEBUGGING - obviously completly ruins any performance gains // bool BinaryHeap::checkHeapValidity() { bool lHeapValid = true; // For the heap to be valid the zeroth element must be the lowest in the set and // the HeapPosition of each element must be correct for (long loopIndex = 0; loopIndex < m_ElementsInList; loopIndex++) { if (p_mBinaryHeap[loopIndex]->MapElement->m_FScore < p_mBinaryHeap[0]->MapElement->m_FScore) { lHeapValid = false; break; } if (p_mBinaryHeap[loopIndex]->HeapPosition != loopIndex) { lHeapValid = false; break; } } return lHeapValid; } // Simply returns the minumum cell in the heap. This does not affect the list const GridCell* BinaryHeap::getMin() { return p_mBinaryHeap[0]->MapElement; } // This method will remove the minimum element from the heap. The caller must delete the returned GridCell pointer. GridCell* BinaryHeap::removeMin() { m_ElementsInList--; //update the amount of elements in heap if(m_ElementsInList != 0) //if we didn't delete the root { swap(p_mBinaryHeap[0], p_mBinaryHeap[m_ElementsInList]); p_mBinaryHeap[0]->HeapPosition = 0; p_mBinaryHeap[m_ElementsInList]->HeapPosition = -1; // Using -1 as this is not a valid heap position value, this it's not in use! reHeap(0); } if ( m_CellsInList.Remove(static_cast<int>(p_mBinaryHeap[m_ElementsInList]->MapElement->m_X), static_cast<int>(p_mBinaryHeap[m_ElementsInList]->MapElement->m_Y), 0) == false) { printf("Error deleting object"); return NULL; } return p_mBinaryHeap[m_ElementsInList]->MapElement; } void BinaryHeap::reHeap(int root) { int child = left(root); if (child <= (m_ElementsInList-1)) { if((p_mBinaryHeap[child]->MapElement->m_FScore > p_mBinaryHeap[child+1]->MapElement->m_FScore) && child < (m_ElementsInList-1 )) //if a right child exists, and it's bigger than the left child, it will be used child++; if(p_mBinaryHeap[root]->MapElement->m_FScore <= p_mBinaryHeap[child]->MapElement->m_FScore) //if root is bigger than its largest child, stop. { p_mBinaryHeap[root]->HeapPosition = root;//parent(new_pos); p_mBinaryHeap[child]->HeapPosition = child; return; } swap(p_mBinaryHeap[root], p_mBinaryHeap[child]); //swap root and its biggest child p_mBinaryHeap[root]->HeapPosition = root;//parent(new_pos); p_mBinaryHeap[child]->HeapPosition = child; reHeap(child); //continue the process on root's new children } else { return; } } // A key method when updating an already existing object in the heap. This will ensure it is corrected following the update void BinaryHeap::updateHeap(int child) { int root = parent(child); if (child <= (m_ElementsInList-1)) { //if((p_mBinaryHeap[child]->MapElement->m_FScore > p_mBinaryHeap[child+1]->MapElement->m_FScore) && child < (m_ElementsInList-1 )) //if a right child exists, and it's bigger than the left child, it will be used // child++; if(p_mBinaryHeap[root]->MapElement->m_FScore <= p_mBinaryHeap[child]->MapElement->m_FScore) //if root is bigger than its largest child, stop. { p_mBinaryHeap[root]->HeapPosition = root;//parent(new_pos); p_mBinaryHeap[child]->HeapPosition = child; return; } swap(p_mBinaryHeap[root], p_mBinaryHeap[child]); //swap root and its biggest child p_mBinaryHeap[root]->HeapPosition = root;//parent(new_pos); p_mBinaryHeap[child]->HeapPosition = child; updateHeap(root); //continue the process on root's new children } else { return; } } int BinaryHeap::count() const { return m_ElementsInList; } void BinaryHeap::clearHeap() { m_ElementsInList = 0; delete p_mBinaryHeap; }
  8. Guys, Thanks v much for your help. It works! YAY! I can finally save my map
  9. Like this? winds up with comp error - error C2664: 'C3DHashtable<T>::forEachElement' : cannot convert parameter 1 from 'void (GridCell *)' to 'IElementProcessor<ElementType> *const ' with [ T=GridCell * ] and [ ElementType=GridCell * ] class X : public IElementProcessor<GridCell* > { public: X() { Map2.Insert(1,2,3, new GridCell(1,2,3)); Map2.Insert(4,5,6, new GridCell(4,5,6)); Map2.Insert(7,8,9, new GridCell(7,8,9)); } void process(GridCell* lGridCell ) { } void demoTheCallback() { Map2.forEachElement(process); } private: C3DHashtable<GridCell*> Map2; };
  10. Hi, Does anyone know if it is possible to use hardware accleration on a part of a dialogue box which displays and OpenGL scene? I have a basic MFC PictureControl hooked into an OpenGL back end effectively to draw me the view. It's killing the CPU and would be nice if I can somehow tell the system to use hardware if avaliable. Thanks Mark
  11. Yep I know, was just trying to get the IElementProcessor to work...
  12. mazelle - with your approach I get a : error C2664: 'C3DHashtable<T>::forEachElement' : cannot convert parameter 1 from 'void (ElementType)' to 'IElementProcessor<ElementType> *const ' with [ T=GridCell * ] and [ ElementType=GridCell ] and [ ElementType=GridCell * ] I can see that there is the diff between the parameter, but no idea on how it should be changed. also needed to add void process(T element) implementation to the C3DHashtable class to stop it complaining about abstract classes. #include "stdafx.h" #include <string> #include <iostream> #include <map> #include <algorithm> #include <vector> using namespace std; struct GridCell { // Alternatice constructor for basic setting up of a cell for path finding GridCell( double X, double Y, long Z) { m_X = X; m_Y = Y; m_Z = Z; } double m_X; double m_Y; double m_Z; }; static const C_numberOfDimensions = 3; class C3DHashtableKey { public: C3DHashtableKey(const int iX, const int iY, const int iZ) { m_iCoord[0] = iX; m_iCoord[1] = iY; m_iCoord[2] = iZ; } bool operator<(const C3DHashtableKey & rhs) const { return std::lexicographical_compare(m_iCoord, m_iCoord + C_numberOfDimensions, rhs.m_iCoord, rhs.m_iCoord + C_numberOfDimensions); } private: int m_iCoord[C_numberOfDimensions]; }; // the interface (say in your case) template <typename ElementType> class IElementProcessor { public: virtual ~IElementProcessor() { } // does something to passed element virtual void process( ElementType element ) = 0; }; template<typename T> class C3DHashtable : public virtual IElementProcessor<T> { private: std::map<C3DHashtableKey, T> m_map; public: C3DHashtable(void) { } ~C3DHashtable(void) { } void process(T element) { } void Insert(const int x, const int y, const int z, T value) { m_map.insert(std::make_pair(C3DHashtableKey(x, y, z), value)); } void forEachElement( IElementProcessor<T>* const elementProcessor) { for (std::map<C3DHashtableKey, T>::iterator it = m_map.begin(); it != m_map.end(); it++) { elementProcessor->process( it->second ); } } }; template <typename ElementType> class X : public virtual IElementProcessor<ElementType> { public: X() { Map2.Insert(1,2,3, new GridCell(1,2,3)); Map2.Insert(4,5,6, new GridCell(4,5,6)); Map2.Insert(7,8,9, new GridCell(7,8,9)); } void process(ElementType element ) { } void demoTheCallback() { Map2.forEachElement(process); } private: C3DHashtable<GridCell*> Map2; }; int main() { X<GridCell> x; x.demoTheCallback(); }
  13. mattd, I've had a go with your example in my app, getting a compilation error: error C2784: 'void C3DHashtable<T>::forEachElement(C &,void (__thiscall C::* )(const T & ))' : could not deduce template argument for 'void (__thiscall T1::* )(const T & )' from 'void (__thiscall X::* )(const GridCell &)' with [ T=GridCell * ] and [ T=GridCell * ] Can you see where I've got this wrong. An abridged version of my code below (I'm not 100% about the functionality, but is does at least exibit the same compilation problems. Thanks Mark #include "stdafx.h" #include <string> #include <iostream> #include <map> #include <algorithm> #include <vector> using namespace std; static const C_numberOfDimensions = 3; class C3DHashtableKey { public: C3DHashtableKey(const int iX, const int iY, const int iZ) { m_iCoord[0] = iX; m_iCoord[1] = iY; m_iCoord[2] = iZ; } bool operator<(const C3DHashtableKey & rhs) const { return std::lexicographical_compare(m_iCoord, m_iCoord + C_numberOfDimensions, rhs.m_iCoord, rhs.m_iCoord + C_numberOfDimensions); } /* bool operator==(const C3DHashtableKey & rhs) const { return std::equal_range(m_iCoord, m_iCoord + C_numberOfDimensions, rhs.m_iCoord, rhs.m_iCoord + C_numberOfDimensions); } */ private: int m_iCoord[C_numberOfDimensions]; }; template<class T> class C3DHashtable { private: std::map<C3DHashtableKey, T> m_map; public: C3DHashtable(void) { } ~C3DHashtable(void) { } void Insert(const int x, const int y, const int z, T value) { m_map.insert(std::make_pair(C3DHashtableKey(x, y, z), value)); } template <class C> void forEachElement(C& inst, void (C::*callback)(const T&)) { for (std::map<C3DHashtableKey, T>::iterator it = m_map.begin(); it != m_map.end(); it++) { (inst.*callback)(<C3DHashtableKey, T>); } } size_t getNoOfMapElements() { return m_map.size(); } }; struct GridCell { // Alternatice constructor for basic setting up of a cell for path finding GridCell( double X, double Y, long Z) { m_X = X; m_Y = Y; m_Z = Z; } double m_X; double m_Y; double m_Z; }; template <typename T> class map { public: map(const T& a, const T& b, const T& c) : a(a), b(b), c(c) {} template <typename C> void forEachElement(C& inst, void (C::*callback)(const T&)) { // example use of callback (inst.*callback)(a); (inst.*callback)(b); (inst.*callback)(c); } private: T a, b, c; }; class X { public: X() { Map2.Insert(1,2,3, new GridCell(1,2,3)); Map2.Insert(4,5,6, new GridCell(4,5,6)); Map2.Insert(7,8,9, new GridCell(7,8,9)); } //: m("foo", "bar", "baz") {} void callback(const GridCell& t) { } void demoTheCallback() { Map2.forEachElement(*this, &X::callback); } private: C3DHashtable<GridCell*> Map2; }; int main() { X x; x.demoTheCallback(); }
  14. Neural Networks

    Self Organising Feature Maps I found to be the simplest to get my head around: http://en.wikipedia.org/wiki/Self-organizing_map