Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Author
Message
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 17th Oct 2008 04:00 Edited at: 20th Oct 2008 02:12
Hullo all. I'm Aaron J. Miller and I'll be teaching you how to write your own GUI in DBPro.

Firstly, I'm going to discuss GUI theory, in my next post I will show some code to go with this theory and document it as well as I can.

Prerequisits (What You Need)
* x86 PC with Windows XP or Windows Vista installed (Though anything DBPro supports will work)
* An understanding of arrays
* My Advanced 2D plugin (unreleased, will be given in next post as-is [text isn't working correctly])
* An understanding of the Dark Basic Pro language

Recommended Prerequisits
* nVidia 8400 GS graphics card
* An understanding of linked lists
* An understanding of memory management
* An advanced understanding of programming theory such as pointers

What a GUI Is
A GUI, or "Graphics User Interface" is a way in which the end-user to a piece of software may interact with that software. For example, I am writing this text here in an edit control, which is a child window of a web browser control, which is a child window of an overlapped window belonging to Mozilla Firefox.

GUIs often involve a parent/child relationship which can be thought of as a tree. Each node of a tree belongs to a parent. All nodes in level one are considered subnodes of the "root" (the main tree). These subnodes are GUI windows. A window is an element of a GUI - it is not necessarily a box with a title bar.

Overlapped windows or Captioned windows are able to be moved by the user clicking on them. These windows will be referred to as draggable windows.

Child windows are windows which belong to other windows (another window besides the desktop is it's parent) and usually cannot be moved. Child windows which cannot be moved are referred to as controls.

Typically, a control retrieves input from the end user and is the main source of interaction to the program. Overlapped windows are just ways to hold these and categorize them.

How Our GUI Will Work
Our GUI will use a linked list AND an array. We will manage our own linked list as is handled in languages such as C and C++ - for educational purposes (I like to know exactly what I'm coding).

Our GUI will use index numbers, but they will be retrieved automatically, and use some fancy bit-twiddling (bitwise operations) that may scare you. Don't be scared, you will be a better programmer for understanding the method.

Finally, our GUI will use a plugin I'm working on called Advanced 2D - which is very close to the functionality of Direct3D and is not recommended for use with novices, however it provides functionality I require for the GUI that simply can't be delivered from DBPro's Basic 2D functions (It's called "Advanced" because it's basically an upgrade from the "Basic" ).


Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
Zotoaster
17
Years of Service
User Offline
Joined: 20th Dec 2004
Location: Scotland
Posted: 17th Oct 2008 15:55
Oooh, this will be very interesting Aaron. I've made my own share of GUI systems in the past, but rarely have I ever properly gone about a parent/child/tree type of relationship.

Just a question before the tutorial starts: The linked lists that you'll be making - will these be necessary, or will DBPro's array commands suffice?

I'll stick this in the tutorials thread once the first proper entry of it comes in.

Alfa x
16
Years of Service
User Offline
Joined: 1st Jul 2006
Location: Colombia
Posted: 17th Oct 2008 17:37
I will be reading this everyday, thanks!
Sasuke
16
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 17th Oct 2008 18:07
As you know, I've also made my own share of GUI systems aswell, should be interesting to see how yours are made. Can't wait to jump into the GUI theory with you and the other guys

A dream is a fantasy, if you achieve that fantasy it was never a dream to begin with.
wildbill
16
Years of Service
User Offline
Joined: 14th Apr 2006
Location:
Posted: 17th Oct 2008 20:25
Just looked at all the GUI systems I have made (6 total). Though I am perfectly satisfied with them, its still nice to look at someone elses approach.
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 18th Oct 2008 00:50 Edited at: 18th Oct 2008 00:57
Hullo again, all.

GUI Tutorial : Setting Up Our Environment
Getting Started
Well, assuming you meet all the prerequisits for this tutorial, you should be ready to start coding. Follow the steps below:
1. * Open the Dark Basic Professional or Codesurge editor
2. * Create a new project (You can call it "GUI Tutorial" (no quotes))[/i]

Now that DBPro is open, you should define several constants. These constants will ease our development as they are part of what is known as the preprocessor. The preprocessor is responsible for parsing a specific set of code before any other code in an effort to alter the source code somewhat dynamically during the compilation process. Dark Basic Pro's pre-processor is rather limiting, however, so I wouldn't recommend looking too much into what a pre-processor is. In Dark Basic Pro, you have several preprocessor commands, listed in Source Code 1-1.

The constants you should add, and their values are listed in Source Code 1-2. They are explained below.

DRAW_TYPE_BOX : 0 - This is used by the Advanced 2D plugin as a specific primitive type - it's Basic 2D equivalent is the BOX command
DRAW_TYPE_TRIANGLE : 1 - This is used by the Advanced 2D plugin as a specific primitive type - It has no Basic 2D equivalent
DRAW_TYPE_LINE : 2 - This is used by the Advanced 2D plugin as a specific primitive type - It's Basic 2D equivalent is the LINE command
DRAW_TYPE_POINT : 3 - This is used by the Advanced 2D plugin as a specific primitive type - It's Basic 2D equivalent is the DOT command
MAX_GADGETS : 512 - This will be the maximum number of gadgets our app will support. You can increase and decrease this value as you see fit. The lower the value, the less memory will be used. The higher the value, more memory will be used
CLASS_WINDOW : 1 - Since our GUI is based off of Classes we will specify a simple integer value to designate the WINDOW class - use this as the class
NUM_CLASSES : 1 - This is some "lazy" code that specifies how many classes there are

The other constants are just COLOR VALUES. These are used to adjust the color scheme.
NOTE: To improve your GUI, I would recommend that you create an additional array of color values so that color schemes may be changed, instead of use static values.

Defining Types
Our GUI relies on the use of User Defined Types. A user defined type (or UDT for short) is a structure which we may use to hold multiple values into one, easily manageable type - as the name implies. We require UDTs to keep track of window data, which may fit in one UDT as an easy to manage linked list item. Before I get carried away with what we're going to do next, I suppose I should show you exactly what our window UDT looks like - have a look at Source Code 1-3 for the complete structure of the window. The structure is explained below:

tWindow
* exist (boolean) - Set to 1 if the window exists, 0 if it does not
* class (dword) - This is the class of the window, for an overlapped window set to CLASS_WINDOW (1)
* flags (dword) - Contains miscellaneous information about the window, such as rather or not it has a close box, can be dragged, can be resized, minimized, maximized, etc.
* text$ (string) - Contains the NAME of the window. This value is displayed in the title bar of the window if it is an overlapped window with a caption.
* x, y (integers) - These contain the X and Y position of the window. When X is 0 and Y is 0 these denote the TOP LEFT portion of the screen.
* w, h (integers) - These contain the WIDTH and HEIGHT of the window. These should NEVER be 0 or larger than the screen width and height.
* fgCol, bgCol (dwords) - These are colors used for drawing text and certain graphical operations.
* lcCount, mcCount, rcCount (integers) - These are used to keep track of input. When the user left clicks in the window, lcCount is increased. When the user middle clicks in the window, mcCount is increased. And, of course, when the user right clicks in the window rcCount is increased.
* gadgetData, userData (integers) - gadgetData is used internally by the class controlling the window, and userData may be used by the programmer to store data specific to that window.
* parentGadget, nextGadget, prevGadget, firstChild, lastChild (integers) - These are used to manage the linked list structure. parentGadget is the index to the global window array. nextGadget and prevGadget point to the neighboring or sibling windows (other children of the parent), and firstChild and lastChild point to the first and last children gadgets of this window, respectively.

Out of all of those fields in the UDT you're probably most concerned about the linked-list management ones. Well, try to draw yourself a diagram of how these linked-list structures may look in a gui. For example, a parent window will have a record of only TWO of its children, but the children themselves will have records of all of their siblings. This enables full traversal of the linked list because each child window may be the potential parent of several more children - allowing very many levels (or generations if you like the hereditary idea of it - for example a full family tree). Currently, however, we will concern ourselves only with the top level windows and the "system window" (the desktop, or root if you prefer).

Managing Our Data
Well now, the first thing we need to do is declare an array of our window UDT. This isn't difficult at all - make sure it's global. For its number of windows, set it to the MAX_GADGETS define.

CAUTION: Unlike C/C++, DBPro's element count for the array is actually the number input + 1; meaning that the value that you pass to DBPro as the element count is actually the last index number - we rely on this here.

Well, this is the hardest part for ME to explain - how a linked list works. It's relatively VERY easy once YOU have the concept down - it's just a matter of writing the code for it. You can use linked list for ANYTHING - managing your in game entities, a list of events, managing levels, materials, or other resources. It's all there as something relatively VERY easy - just a bit tedious in DBPro since DBPro lacks any form of OOP or template classes all-together!

Anyways, the linked list system we will use is an entire parent/child hierarchy which allows for an infinite (in terms of how much memory is available) series of nodes. HOWEVER, the version of that we will be using will use a fixed sized array for a) Stability, b) Memory efficiency, and c) It's easiest to understand and prevents what is known as a MEMORY LEAK. But you'll learn about memory leaks later on - they're pure evil, they are. :/

The first thing should learn about linked lists is how to set them up. Well, we've already filled in our linked list data fields for our window UDT, so we've got that portion setup. We've now got our global array of these setup as well. So, the next step is naturally the creation of them. As mentioned earlier, we have a ROOT node in the linked list (array index 0). This node is considered the desktop window, so before anything else we MUST set this node up.

Setting up the root node is dead simple. Firstly, set ALL fields in it to zero. The root node will NEVER have a parent node, it will never have a previous or next node, it will ONLY have the first and last child node references - which are initially set to zero.

The next step is adding a node. Firstly, if the parent value is ZERO (0) then the node is created as a child to the root node, otherwise it is created as a child of the node specified. Since GUI elements are allocated dynamically, we need a way of finding a free index in our window array and checking if an item exists. If you recall the window UDT there was an 'exist' field which made this task somewhat easier. What we'll do to find an unused index is loop through the maximum number of entries. If an entry is not used then it will be returned. Once the maximum number was reached, we will return 0 (since 0 is always used it can be considered valid, even though array indices start at 0). For an example of this, look at Source Code 1-4.

Since we're using a class-based GUI approach, we'll also need a way of checking to see if a class exists. Since a function call is cleaner (though slower) we'll use the function call method. Essentially, verifying if a class is valid or not is a simple task of checking if the class value is within the proper range of classes. Look at Source Code 1-5 for an example of this function.

NOTE: Function calls ARE slower than doing the code yourself, but since this is only a tutorial on getting a GUI up and running, we won't worry about performance optimizations such as getting rid of functions, at least not yet.

Now, to build that FindFreeWindow() function, all you have to do is continuously check if a gadget exists or not. This is VERY easy, anyone could do it. Just loop through every item in the window array and check if the exist field is 1 or not.

Once you've found a valid index, you should entirely zero-out the array element belonging to that index, and add it to the end of the linked list. To add it to the end of the linked list you do the following:

ItemToAdd.Parent = Parent
ItemToAdd.PrevItem = Parent.LastChild
ItemToAdd.NextItem = 0
ItemToAdd.FirstChild = 0
ItemToAdd.LastChild = 0

Although, you can just as easily add the item to the front of the list, I like the idea of managing the list somewhat more like a queue (If you don't know what a queue is, then you can look it up on wikipedia or in the DBPro manual).

When you want to remove an item from a linked list, you would point the previous and next items to each other after undergoing a recursive step of deleting every child item. The following shows how to do this:

While ItemToRemove.LastChild <> 0
CALL THIS FUNCTION(ItemToRemove.LastChild)
EndWhile
ItemToRemove.NextItem.PrevItem = ItemToRemove.PrevItem
ItemToRemove.PrevItem.NextItem = ItemToRemove.NextItem
If ItemToRemove.Parent.FirstChild = ItemToRemove
ItemToRemove.Parent.FirstChild = ItemToRemove.NextItem
EndIf
If ItemToRemove.Parent.LastChild = ItemToRemove
ItemToRemove.Parent.LastChild = ItemToRemove.PrevItem
EndIf

You would use a method like this to also, for example, move a window to the front of the list. In this event, you would use that same removal code, but also add the following:

ItemToMove.PrevItem = ItemToMove.Parent.LastChild
ItemToMove.NextItem = 0
If ItemToMove.Parent.LastChild <> 0
ItemToMove.Parent.LastChild.NextItem = ItemToMove
EndIf
ItemToMove.Parent.LastChild = ItemToMove
If ItemToMove.Parent.FirstChild = 0
ItemToMove.Parent.FirstChild = ItemToMove
EndIf

We'll learn a bit more about linked lists later on when we explore more on parent/child relationships, user input, and rendering in the next post. For now, I've merged all of this theory into one set of source code, with some extra functions. Don't try to run the code though. In the next tutorial, we'll have it able to be compiled, and you'll be able to move windows around, for now, try to stick all this in your head! Check out Source Code 1-6 for the full code to this part of the tutorial.

NOTE: Because we're using arrays, we reference everything by index and access the field from the array. That's why the code above isn't listed as source code - it's pseudo code.

SOURCE CODE 1-1


SOURCE CODE 1-2


SOURCE CODE 1-3


SOURCE CODE 1-4


SOURCE CODE 1-5


SOURCE CODE 1-6




OFF TOPIC (Response to comments) This is not part of the tutorial
Thanks. I was expecting a few people getting mad because I posted this without the first actual part of the tutorial, but I'm quite relieved to see that this is not the case, thank you.

@Zotoaster
The array part of it is necessary for the purpose of stability since we are using indices instead of pointers - which are pure evil in DBPro. The linked list is the most efficient system, without it the parent/child hierarchy simply won't work. So to answer your question, yes, the linked list is entirely necessary. DBPro does, however, contain linked list commands, but I feel it's more important to understand how they work so they may be reused for other systems.

Cheers,

-naota

NOTE: The Advanced2D plugin (alpha 1) is attached below - you will be needing it for the next part of the tutorial

I'm not a dictator to those that do stuff for me by will. Only those who don't.

Attachments

Login to view attachments
Zotoaster
17
Years of Service
User Offline
Joined: 20th Dec 2004
Location: Scotland
Posted: 18th Oct 2008 18:13
Well, the first entry of the tutorial is in - it's now in the tutorials thread. Looking forward to the rest.

Mobiius
Valued Member
19
Years of Service
User Offline
Joined: 27th Feb 2003
Location: The Cold North
Posted: 18th Oct 2008 19:46
Quote: "Recommended Prerequisites
* nVidia 8400 GS graphics card"


That's a shame, I only have a 7600GS card. (Unless it runs on lower spec'd cards?)

3700+ Athlon 64 - Geforce 7600 GS - 2GbDDR2 RAM - 40Gb Hdd (In this pc) - Windows Vista Ultimate (x86)
Diggsey
16
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 18th Oct 2008 20:47
Aaron, why not use 'array insert at bottom' if you run out of spaces in the array?
That way, you keep the indices the same, while expanding the array if necessary. Obviously, it might be a good idea to have an absolute maximum, but you don't have the maximum number of items there all the time.

Anyway, tutorial looks good so far

[b]Yuor signutare was aresed by a deslyxic mud...
BOX2D V2 HAS HELP FILES! AND A WIKI!
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 18th Oct 2008 23:24
GUI Tutorial : Window Procedures
Alright, before we start drawing the window, we want to look into how to update the window - and all the window controls (don't worry about controls just yet though). The first thing we've gotta do is open up the DBPro project! Once you've done that, we may begin.

SPECULATION: In Microsoft Windows window classes have what is known as a window procedure. The procedure is called every time an event occurs to that window. The procedure takes 4 values - the handle to the window being affected, what kind of message we're getting, and two values dependant of the message. This "WndProc," as it is called, also returns a value which can help convey effectiveness of the procedure. These WndProcs are dependant of the class being used - we will follow a similar method with our GUI, and perhaps later expand on it.

What we need to do first is provide a way of handling input before we attempt to use input (did that make sense?). Input refers to data which the keyboard, mouse, joystick (etc) sends to the program. This data is known as input data. An Input system is responsible for managing this data. We won't worry about keyboard input just yet, but we will worry about mouse input, which is probably one of the more non-visual aspects you were looking forward to for this GUI.

Well, to get started lets add some variables. We'll use FIVE (5) integers to describe this data. They are g_oldMouseClick, g_mouseClick, g_mouseX, g_mouseY, and g_mouseOver. Don't worry about the g_mouseOver variable right now - the other variables should be pretty self explanatory.

TIP: You can put these input values, and future input values, into a single type and make a global variable declaration as that type. This will make your code a bit more module.

The next thing we've got to do is create our own update function. This update function must care for all these input values, then will later manage the windows and send them input. A pseudo update function is provided in Source Code 2-1.

NOTE: It's actually MUCH more efficient to use a GOSUB instead of a function. There's a small overhead within and outside a function call which makes functions less efficient than a simple GOSUB/RETURN combination. I'd recommend using a GOSUB instead of a function for efficiency.

Now that we've got our function, we'll want to be doing something with the mouse input. Well, we'll need to create another function - a function to check the closest window (in terms of z-order) at a specific point. What we'll do here is make a recursive function that will continuously look through the subnodes of a node in our window tree. For an example of this function (I can't seem to find a good way to write pseudo code for the algorithm) check out Source Code 2-2. Make sure you understand what the code is doing before continuing.

Now, we can change our UpdateGUI function. Instead of setting g_mouseOver to zero, we will set it to InWhatWindow(0, g_mouseX, g_mouseY). This will allow the g_mouseOver value to contain the index number of the window the mouse is currently hovering over. This is quite important, so make sure you understand this!

Moving On To Procedures
Okay, now that we've got all this mouse input stuff sorted out, I think it's time we move on to something a bit more important - window procedures. Since Dark Basic Pro doesn't allow functions to be called through function pointers, we have to add a bit of overhead to calling a particular classes procedure, but this is fine as we won't have that many classes by the time this tutorial is done - and if we do then I'd recommend you to checking out some of the more advanced plugins that do allow function calls (Have a look at the Matrix1 plugin set by IanM).

So, here's what we're going to do. We're going to provide a standard function which will be called once EVERY update (instead of per input, like windows). This is because this particular method is easiest for our task. We want to get to a point where we can test everything first, then we might expand on this later, or rewrite it.

Anyways, this standard function, we will call it "__Gadget_Proc__" (the underscores are because this is an INTERNAL FUNCTION - All internal functions will be formated in this way). The __Gadget_Proc__ will update some general things (such as the click count) and call the more specific window procedures based on the class of the window.

NOTE: The window procedure of a class is NOT responsible for drawing the window. A separate per-class function will be used for this, as well as a general procedure which will be called to prepare the class-specific procedure for drawing, and then call that procedure.

The __Gadget_Proc__ (and all class procedures which are called by it) take one value - the index number of the gadget it is supposed to update. It will not return any value. The first thing I would do with this procedure is check if the index value it was passed is the same as the value of g_mouseOver. If it is then check the g_oldMouseClick value for 1 (left), 2 (right), or 4 (middle) and if the g_mouseClick value is currently 0 (this is known as releasing a mouse button). Next (since there's not much else you can do with it currently) you should check what the class of the window is, and then call its specific function.

For draggable windows, we will call this the __Window_Proc__ function. The __Window_Proc__ function is responsible for dragging the window (later we will move on to resizing the window). For dragging a window, we will require THREE (3) integers. These are g_dragWnd, g_dragX, and g_dragY. Their meanings are listed below.

g_dragWnd - If this is larger than zero then a window is being dragged. The value of this is the index number of the window being dragged.
g_dragX - When you click on a draggable area of a window, you are clicking in the WINDOW'S coordinate system. This system is relative to the top-left of the window (the window's position on the screen). This is the horizontal component of that coordinate system.
g_dragY - When you click on a draggable area of a window, you are clicking in the WINDOW'S coordinate system. This system is relative to the top-left of the window (the window's position on the screen). This is the vertical component of that coordinate system.

Before I discuss more about dragging, we need a way to call ALL the window procedures - in order. So, what we will do is provide a function to do this for us since the function can call itself. We'll call it __Call_Window_Procs__, and it will take a single parameter - the index of the window to update. How it works is it will first call itself on each one of the window's children, then it will actually update the window it was called for. If you understand how to traverse through the linked list now, this shouldn't be difficult for you at all. IF it is too difficult for you to understand (bulls*** code thief!) then you can have a look at SOURCE CODE 2-3 for an example of this function.

NOW THEN, we must start work on dragging a window (I know, before drawing the window... My reason for this is simple - If I show you how to draw a window first then you're going to go overboard with the graphics and won't do the boring bits (of course this could mean I may lose some readers too, lol)). Let's discuss how to drag a window, shall we?

Firstly, my approach at this is to check if a window should be dragged through the window procedure (this is how Microsoft Windows handles this too). We can determine if a window should be dragged if the g_mouseClick value is 1, and g_oldMouseClick value is 0. If that condition is true, no other window is currently being dragged, AND the window belonging to the procedure is the one the mouse is currently hovering over, then the window may be dragged.

In the event that a window does get dragged, we need to determine the point in the window's coordinate system that the user clicked (Top-left in the window coordinate system is 0, 0, but on the screen could be anything, for example 357, 268). To do this, we subtract the position of the mouse from the position of the window and put the result in the g_dragX and g_dragY values.

We do, however, do two things in our UpdateGUI function to handle dragging. The first of the two is checking if the g_mouseClick value is 0. If it is zero then we know that the user can't POSSIBLY be dragging a window, so we set the g_dragWnd, g_dragX, and g_dragY values to zero if this is true. The second is to check if a window IS in fact being dragged, if so then we drag the window!

Once we have a window to drag, we can determine it's position by subtracting the position of the mouse by the position of the window and placing the result as the window's position (windowPosition = mousePosition - dragOffset). There are some extra steps, which should be easy to understand, for handling controls. DO NOT WORRY ABOUT THESE STEPS. They will be explained in another "chapter" of the tutorial.

Okay, NOW we can draw a window! .... No, not really. Now we can PREPARE to draw a window. What we're going to do is traverse our linked list, draw the window, then call the function again for each child window of the parent window. This is what we've been doing all along, really (the algorithm). It's been shown in other steps, for example, checking what window a point is in, and updating all the windows, etc - so I won't provide the source code for this (until the end of this chapter) - if you need help, just alter the previous source code.

Anyways, we will follow the same steps as the window procedure, the only difference is the use of the ADVANCED 2D plugin. You see, my Advanced 2D plugin was actually created because of a missing feature in DBPro (not to mention it improved my performance by about 400+ FPS!). This feature is the use of VIEWPORTS.

A viewport is an area which allows objects and other primitives to be drawn. Since our window is a box, we want to "clip" what's inside of that box to the position of the window. That's what we need to do. Take, for example, you have a line that you want to draw. Say that the line was supposed to go from 0, 0 to 640, 480 in the window. Now imagine that the window was resized to about 400, 300. The line would end OUTSIDE of the window. You could try to readjust the position of the line to remain in proportion, but this can be very inefficient. With the use of a viewport, if the size of the window is changed to 400, 300 instead of remaining at 640, 480 - the line will still be drawn correctly, AND be clipped so that it doesn't interfere with other windows or go outside the window. Some people have solved this by using bitmaps, but this is a rather slow method.

Some advanced terms are used in the plugin, such as stream sources, primitive types, vertex buffers, etc. Don't worry about this! I'll explain them as best as I can, but I'll do it in another chapter - for now; just assume that the window drawing procedures I've already made look pretty.

Now, you should create a gadget and perform some standard DBPro updates (such as setting sync on). This is shown in the full source code.

I believe that covers pretty much everything you need to know for this chapter - have a look at the complete source code in Source Code 2-4. Up next, controls!

NOTE: The demo is provided as a compiled EXE at the bottom right of this post as an attachment (labeled 'download'). Run this EXE to get an idea of what we've just done.

SOURCE CODE 2-1


SOURCE CODE 2-2


SOURCE CODE 2-3


SOURCE CODE 2-4


OFF TOPIC (Response to comments) This is not part of the tutorial
Diggsey, this would not teach people how to handle a linked list for themselves - I'm trying to teach how to handle these things so that they will be able to reuse what they learn in languages that don't have these commands - if that answers your, erm, statement.

Mobiius, I only recommend the nVidia 8400 GS because that is what I'm using - it's not a requirement, this should work on every card supporting Direct3D 9.0c.


Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.

Attachments

Login to view attachments
Diggsey
16
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 19th Oct 2008 01:09
@Aaron
Name one language that doesn't allow you to allocate data at runtime

[b]Yuor signutare was aresed by a deslyxic mud...
BOX2D V2 HAS HELP FILES! AND A WIKI!
Zotoaster
17
Years of Service
User Offline
Joined: 20th Dec 2004
Location: Scotland
Posted: 19th Oct 2008 01:57
Quote: "Name one language that doesn't allow you to allocate data at runtime"


This is really not the best way about making variable sized lists :p

On another note, I don't think "array insert at bottom" is a linked list command. Linked lists are too slow to get random access. I think basically what it probably uses is a linked list of stack arrays. This means you get the speed of arrays (just about), the feel of a linked list, and somewhat variable sized lists... I think this is what std::vectors in C++ does anyway, and chances are that that's exactly what DBP uses.

Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 19th Oct 2008 03:00
Diggsey, pointers in DBPro suck.

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 20th Oct 2008 02:09
GUI Tutorial : Controls
Well, you all know what a control is; it's a GUI element which resides as a child of a window or other form. We'll be implementing controls in this chapter of the tutorial. Here's a list of the types of controls we'll create:

* Label - This control does NOTHING but display text.
* Button - This control allows you to press it.
* Check Box - You can toggle the "check" state of this control.
* Radio Box - Out of ALL the radio-box controls of a parent, only one can have an "on" state.

The first thing we're going to have to do here is create some more classes! The reason for this is the 4 controls we'll be implementing all operate differently - they are different. Thus we must implement classes.

If you haven't already done so, open up your DBPro project. Now that it is open, add the following constants (set them to the value after the colon):

CLASS_LABEL : 2
CLASS_BUTTON : 3
CLASS_CHECKBOX : 4
CLASS_RADIOBOX : 5

And change the value of NUM_CLASSES to 5. Next, we will add our control procedures. You do recall that all classes have two procedures, don't you (If not you're skipping ahead - go back). CURRENTLY, for the label class the update procedure is entirely pointless (it will do nothing), but later on MAYBE I'll look into allowing you to select text from the control - which would require the update procedure. So, just create a blank update procedure for the label control - call it __Label_Proc__. (Remember that it must accept an ID value).

Now that you've created the blank procedure, make sure __Gadget_Proc__ calls it if the class of the window is equal to CLASS_LABEL. Once you're finished with that, create the __Draw_Label__ procedure, which has the same syntax as the __Label_Proc__ procedure. You will not be doing anything advanced in this procedure - just call the ShadowText function I provided in Source Code 2-4 with the gadget's foreground and background colors as the fg and bg parameters -- draw the text of the control. Review Source Code 3-1 for example source code to these functions.

Before you attempt to run these modifications, add the following statement RIGHT AFTER the __Redraw_Windows__() statement in UpdateGUI():

Set Viewport 0, 0, screen width(), screen height()

This will ensure that the viewport is returned to where it needs to be. (Once you've done this, you can run the code).

BUTTONS
Okay, next we're going to work on buttons. (That's correct! It really is very easy to add in a control). Buttons are very simple. But before we get started on them, lets define what we want our button class to do.

Well, firstly it's always nice to enable a button to have 3 different color schemes. One for when a button is completely idle (normal scheme). One for when the mouse is hovering over a button. And another one for when the button is being pressed. Next, we want to make sure that the text that we draw is always centered in the button - it makes the button look nicer. That's all we need to worry about for buttons - simple, right?

So, lets get started on buttons! The first thing you need to do is create the __Button_Proc__ update procedure. The following is how we will layout the procedure:

-> Is there a left click?
--> Did the left click just occur?
---> When the left click occured, did it happen on the button?
----> The button is now in a pressed state (windowData = 2)
-> Is there no left click?
--> Is the mouse currently over the button?
---> The button is now in a highlighted state (windowData = 1)
--> Is the mouse NOT currently over the button?
---> The button is now in an idle state (windowData = 0)

I've made a simple version of that procedure - I didn't bother to optimize it, but you can if you like.

NOTE: If you can recall from previous chapters, there is a 'windowData' field in tWindow type - that is the field I was refering to when I said 'windowData' several times earlier.

Now that we've got the button update procedure, we should get started on the button drawing procedure. But first, we'll add some color scheme defines so that we know what color to draw the buttons, and can change these colors easily. Look at Source Code 3-2 for a list of these constants.

NOTE: The BTI stands for "button idle." BTH for "button highlighted." And BTP for "button pressed."

Now we can start on the drawing procedure of the button (__Draw_Button__). What we'll do in this procedure is check the current state of the button (It's stored in the windowData field of the button's array entry). If the state is equal to 0 then the button is idle, and should be drawn with the IDLE color scheme. If the state is equal to 1 then the button is in a highlighted state, and should be drawn with the HIGHLIGHTED color scheme. Finally, if the state is equal to 2 then the button is in a pressed state, and should be drawn with the PRESSED color scheme.

After that, we will find the X and Y coordinates that we will draw the button's text at. To do this we will find the position of the button and add half the size of the button minus half the size of the text. In other words, we will use the following formula.

TextX = (ButtonWidth / 2) - (TextWidth / 2)
TextY = (ButtonHeight / 2) - (TextHeight / 2)


DarkBasic Pro provides functions for finding the text's width and height, so we will use those functions (they are called TEXT WIDTH, and TEXT HEIGHT -- they both take a single string value and return an integer - the size). The PROPER centering of the text we will do ourselves (The CENTER TEXT function only works across the X axis, not the Y axis and we want to center on both axis).

For good looks, we will use the ShadowText function yet again (In fact, there are few times that I think I won't use that function for our controls). If you're having trouble producing this function (And I bet you will - I haven't showed you how to use the Advanced 2D plugin yet) the source code for BOTH __Button_Proc__ and __Draw_Button__ are listed in Source Code 3-3. Now all you have to do is make sure that __Gadget_Proc__ will call __Button_Proc__ if necessary, and __Draw_Gadget__ will call __Draw_Button__ if necessary - and your button control's added!

CHECK BOXES and RADIO BOXES
I've been writting this tutorial non-stop for about an hour or two now, so I'm going to speed it up. But not just because I'm getting sick of writing all this down and testing code, but also because you should be able to figure out how to do checkboxes and radioboxes all by your self (ESPECIALLY check boxes). So, I'm going to explain for you the steps you should take.

The main idea to a checkbox is this - if you click the checkbox and its current state is zero, its state will become one. If the state is already one, then it will become zero. You only count a click if it's the RELEASE of a click (two reasons for this are 1; to keep the state from continuously changing and 2; to allow the user to be able to change their mind if they want to (If for example you change your mind mid-click and decide you don't want the box checked - you just move the mouse off the box and release)).

For radio boxes the idea is that if you click a radio box in a group, only THAT radio box will be in the "on" state - all others in that group will be set to the "off" state. A group is basically all the immediate children of a parent that is of a specific class - in other words the radio boxes.

The procedures are __Checkbox_Proc__, __Radiobox_Proc__, __Draw_Checkbox__, and __Draw_Radiobox__. These are outlined in Source Code 3-4.

Conclusion
Finally, the windows were always intended to be partly transparent - so in the UpdateGUI() function, right before the __Redraw_Windows__ statement, do the following:

Alpha Blend On 0

The full source code to this chapter is in Source Code 3-5. Enjoy!

Also, a working executable is provided as an attachment to this post - be sure to download that.


SOURCE CODE 3-1


SOURCE CODE 3-2


SOURCE CODE 3-3


SOURCE CODE 3-4


SOURCE CODE 3-5


I'm not a dictator to those that do stuff for me by will. Only those who don't.

Attachments

Login to view attachments
Zotoaster
17
Years of Service
User Offline
Joined: 20th Dec 2004
Location: Scotland
Posted: 22nd Oct 2008 22:37
I love it. Probably one of the nicest GUI systems I've seen in DBP. Will you be making menu systems?

Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 23rd Oct 2008 01:48
Yes, absolutely. They're structure is the same as a treeview, they're just arranged differently. So I'll be covering those when I cover treeviews.

Currently, the tutorial is in an intermission state. And what I mean by that is "I need to write more code, then write the tutorials, then start releasing them again." So there won't be another chapter to this tutorial for about, say, a week I think (tops). (The reason for such a long time is because I'm also working on another project).

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
Sasuke
16
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 23rd Oct 2008 05:31 Edited at: 23rd Oct 2008 05:51
This is some great stuff Aaron, will have to impliment some of this into my Steam Gui i'm making at the moment. It's works like Steam though offline, i'm making it as a manager for my DB projects and other media stuff (demo soon). Anyway keep up the great work

One more thing, this function make window:


Wouldn't it be easier to create similar functions, just the name ie. MakeLabel and the class is set within them, just saves time and makes more sense when quickly glancing at code. Or a reference function like:



The MakeWindow function name would have to change, something like MakeGuiComponent.

A dream is a fantasy, if you achieve that fantasy it was never a dream to begin with.
Final Epsilon
18
Years of Service
User Offline
Joined: 26th Jan 2004
Location: CA, USA
Posted: 23rd Oct 2008 05:54
These tutorials look really great! So far I've just skimmed through them, but I think I'll maybe take the weekend or so to really sit down and read everything. =)

Cheers,
Finalep
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 24th Oct 2008 02:18
@Sasuke
Thanks. However, I find it to be more efficient (faster) to just use the MakeWindow function (Modeled after Windows NT's CreateWindowExA function). Here is the reason I'm choosing to avoid such a wrapper function:

NON-WRAPPER ASM:


With the wrapper it's like that (minus one parameter), and then all the parameters are pushed again. I find it more efficient to just use the one function.

NOTE: I have spinners ready for the next tutorial (You'll learn a lot about bitwise operations in this tutorial... Believe me ), next up I'll work on tabs, then list boxes (and that will signal the next tutorial set as ready).

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
Sasuke
16
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 24th Oct 2008 03:44
I see, cheers Aaron

Quote: "You'll learn a lot about bitwise operations in this tutorial"


Looking forward to that!

A dream is a fantasy, if you achieve that fantasy it was never a dream to begin with.
GIDustin
14
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 11th Nov 2008 05:11
You didn't forget about us did you?

I have learned so much about GUIs from this. Do you have plans for sliders?
Sasuke
16
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 11th Nov 2008 15:04 Edited at: 11th Nov 2008 15:04
Aaron is currently unavailble at the moment, no internet for awhile cause of moving, but I believe he will find a way to join us once again.

A dream is a fantasy, if you achieve that fantasy it was never a dream to begin with.
Diggsey
16
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 11th Nov 2008 20:44
Well, I saw him on MSN last night

[b]Yuor signutare was aresed by a deslyxic mud...
BOX2D V2 HAS HELP FILES! AND A WIKI!
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 12th Nov 2008 01:07
@Diggsey
And you didn't say hi?

@Others
I didn't even find the time to use MY computer yesterday - I managed to turn it on and log in, but I couldn't get passed that due to the requirement to move a bunch of stuff down stairs.

I'll be working on the tutorial again tonight, and yes I do have plans for sliders. I plan spinners, tabs, sliders, treeviews, menus, comboboxes, listboxes, listviews, scrollbars, etc. (I hate scrollbars, btw -- not my strong suite in a GUI).

The code for the spinners is done, just a small graphical glitch that I don't feel like tinkering with (Could be solved with the use of an image I suppose). The tutorial is getting written, slowly. Sorry for the delay, I really am. :/

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
GIDustin
14
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 12th Nov 2008 01:21
Not a problem. Really useful tutorials are few and far between and I just didnt want to see it die. My cause for concern was after reading this:

Quote: "So there won't be another chapter to this tutorial for about, say, a week I think (tops)"


And that was almost 3 weeks ago.

So you go do what you need to do. I can wait patiently, I swear I can! (I think)
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 13th Nov 2008 01:23
haha, well, if anyone would like to see what I've got done, I'll post it (Keeping in mind it's a work in progress) but if not I'll work on it more.

I did manage to get on my computer last night - for about 10 minutes. But when I got on, I didn't really want to do anything so I just read some old planet zebeth comics I had saved. When I go home today I'll have to pack up most of my room (That is, most of what's left of my room) since I now know I'm moving on Friday.

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 14th Nov 2008 01:16
GUI Tutorial : Spinner Gadgets
What Is A Spinner?
If you don't know what a spinner is, then read this section. If you do know, then you can skip this section. For those who don't know, lets continue. A spinner (or "up-down") control is a control with two arrow buttons on it that allow it to select a value. Pressing the up button of the control will increment this value (holding it will increment the value a bit faster). Pressing the down button of the control will decrement this value (holding it will decrement the value a bit faster). Usually, there is an additional control to the left of the spinner (An edit, AKA text-box control which allows values to be input). Spinners are useful for a variety of reasons - unfortunately I can't find one where a spinner is absolutely necessary (I'm doing this tutorial by request ).

How will our spinner be implemented?
Well, firstly our spinner will NOT use any child windows (buttons). Why? Because they're not necessary - we can squeeze more performance out of the spinner if we rely on just one control (in terms of GPU and CPU times, this would be more efficient). Think about it, if there are two controls attached to the spinner, then that means that for each spinner control, there are really 3 controls. So if you had, say, 9 spinners, there would be 27 controls to update! Quite unnecessary, IMO. Anyways, we'll implement spinners without buddy windows. A buddy window is a window which has the same parent as another window, and communicates with that window, as that window does with it. We won't be using a buddy window because this adds unnecessary complication to our GUI (then again, so does our implementation to begin with ^_^).

The technical aspects of the implementation are this: We'll be using a single integer to hold 3 values through bitwise operations. These 3 values are; the value of the spinner [0-65535], the flags of the control [0-255], and a time-out value [0-255]. The flags let us know which button in the spinner is being highlighted or pressed. The time-out value lets us know how long the button has been held for.

I wrote the following section while working on the code for the tutorial. Please read it, and ignore the inconsistency with the general-tone of this tutorial.

Bitwise Notes
Guess which is slower!
A: x * 2
B: x << 1

They both equal the same answer. If x = 4, then x * 2 = 8 and x << 1 = 16).
Lets look for a second. When multiplying the processor has to do special
arithmetic to ensure an answer is correct. However, if the value in question
only has to be doubled (or multiplied by a power of two) then we can simply
shift the bits left by that power. So, if X = 4 (for a byte) then its bits
are %00000100. The bits for 8 as a byte are %00001000. Since the bits would
only be shifted left once, it's clearly quicker than performing a series of
complicated arithmetic and additional machine code instructions.

This technique can be applied for division by powers of two, but with the
right bit-shift operator, >>. For example, 128 / 2 = 64. 128 >> 1 = 64. It's
essentially the same operation in reverse, and much quicker than division.

NOTE: This technique does NOT work on floating point values, only integers,
dwords, words, bytes, and (probably) DBPro's booleans.

Look at the following operations - they will set a specific bit in an integer
to 0, set a specific bit in a integer to 1, and check what the value of a bit
in an integer is.

CLEAR_BIT(num,bit) { num = num && (0xFFFFFFFF - (1 << bit)) }
SET_BIT(num,bit) { num = num || (1 << bit) }
GET_BIT(num,bit) { is_bit_set = (num & (1 << bit)) }

In addition to all that interesting stuff, you can check if a value is
negative or not (avoiding the use of CMP and a JMP (Or if DBPro actually IS
optimized, a SETG/SETL/SETE/SETGE/SETLE instruction instead of JMP)) by
ANDing the value with 0x80000000. That's because by ANDing a value with
0x80000000 you're checking if the sign-bit has been set (this is why if you
display a number like 0xFFEEDDCC through the PRINT command you get a negative
number). So! Let's make our own ABS function!

function Absolute(num as integer)
if num && 0x80000000 then num = num && 0x7FFFFFFF
endfunction num

As you can tell, bitwise operations can be great performance optimizers if
used correctly in tight loops. Not to mention they're probably one of the
funnest aspects of programming! ^_^

On To Our Spinner Control!
Firstly, to implement this, we'll outline the same procedure as our previous tutorials. Add the class constant, and create two empty functions (One for updating, and one for rendering). But, in addition to that, we're also going to add some additional constants. Flag constants to be exact. If you read the above bitwise notes section then you can see CLEAR_BIT, SET_BIT, and GET_BIT, and understand that every value in any data type is just a series of bits (0s, and 1s). Flags can be "magically OR'd" together through the || operator (You can also use the + operator, but I prefer the || operator). Anyways, we won't have to use CLEAR_BIT, SET_BIT, or GET_BIT to check our flags, we can implement these fairly easily. Do you know how numbers look in binary? Look at the following:
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
1010 = A hex, 10 dec
1011 = B hex, 11 dec
1100 = C hex, 12 dec
1101 = D hex, 13 dec
1110 = E hex, 14 dec
1111 = F hex, 15 dec

Lets say that 1 represents a flag A, 2 represents flag B, and 4 represents flag C. Notice anything in common? Well, 1 = 0001, 2 = 0010, and 4 = 0100. Can you guess what value flag D would have? Flag D would be 8 (1000). The reason for this is these values (They're powers of two) represent specific bits being set. So, the next value after 0x08 would be 0x10, then 0x20, then 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000 (and so on). Or in decimal; 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 (and so on).

Anyways, when flags get OR'd together, it "combines" them. Okay, take flag A, flag B, and flag C for instance, (%0001, %0010, %0100, respectively.) If you have a variable called flags (which should be initialized to zero before anything else), then you would be able to do the following: flags = FLAG_A || FLAG_C Now, if you did that the value would be %0101. If you changed FLAG_C to FLAG_B it would be %0011. And so on. You can also add flags, for example, say the flags variable is 3 (FLAG_A || FLAG_B). You could add a flag like so: flags = flags || OTHER_FLAG.

Now, checking a flag is REALLY easy. You just do a bitwise AND (The && operator in DBPro) on the flags variable with the flag in question to check. If, for some reason, you are confused about this, go ahead and ask me a question. (DO NOT email me, I'm tired of all the spam about "OMG! Wil u give m3 s0urce c0d3 plz?!" - Just post here).

Sorry for the long explanation of what a flag is, and how to use it, but it's necessary information as you're going to add constants for them. We have 4 flags. SPI_FLG_UP_HIGHLIGHT, SPI_FLG_UP_PRESSED, SPI_FLG_DN_HIGHLIGHT, SPI_FLG_DN_PRESSED. (Spinner Flag - Up Highlight, Spinner Flag - Up Pressed, Spinner Flag - Down Highlight, Spinner Flag - Down Pressed).

Remember those update and render procedures you made a little while back? Well, lets edit those. FIRSTLY, our spinner only has on it two "buttons." Neither the spinner, or the button contains any text. So, with this information you should be able to construct the bodies for both the update and render functions for the spinner. Firstly, there's no horizontal/vertical spinners here - I don't see spinners necessary at all, why would I find horizontal spinners necessary? So we know that the top button takes up the top half of the spinner. The bottom button thus takes up the bottom half of the spinner. Now, whenever the user moves the mouse within range of one of these areas, we can set the highlight flag for the corresponding area on. And if the user is clicking the area, we can set the pressed flag on for that area. You should know how to do this from the example above, but if not you can go ahead and look at the source code (cheater ).

NOTE: - We could use the text of the spinner as a way to represent the value of the spinner - and you can do this if you like to avoid certain aspects of bitwise operations. However, the bitwise operations are much more efficient than the text operations, so I'd recommend those. You're only limit is that you have to deal with a limited range of values for the spinner (0 .. 65535). In addition, you could allocate another structure with MAKE MEMORY and then set the windowData as a pointer to that structure, freeing the memory when the window closes, but this isn't something I plan on teaching in DBPro (I want to save you the frustration - If you want to use pointers and other advanced programming concepts, move on up to C++).

As for the render function, all you need to do is draw the buttons and draw arrows where the text should be. To do this I just drew 2 boxes, 5 lines, and 2 triangles. Again, if you're confused as to how to do this (I didn't tell you how to draw a triangle with Advanced2D, so I expect you would be) then you can just have a look at the source code. Keep in mind, that when drawing you'll want to check the flags of the spinner to see how things are done. Not doing this will yield an ugly looking spinner control (Then again, it's a sort of ugly GUI, might as well match the style ).

And that's it! Just create your spinner and let it draw. The source code to this tutorial is shown below, and a working executable is attached. Please realize I was only able to put bits and pieces of this tutorial very little at a time due to some personal issues (Moving, packing, dealing with idiots, lack of motivation, etc). I apologize greatly for the inconvenience as, apparently some people seem to like the tutorials I've been writing. Now, please realize that my method for writing GUIs isn't the ONLY method out there. It's just the one I chose for this tutorial. It's relatively simple, and does rely on a renderer. There are much more complex GUIs, and I chose to write a simple one that can easily be expanded upon. It is a DBPro GUI system, so bare with me.

NOTE: - These are the reasons this tutorial took so long to complete:
1. Lack of motivation
2. Installation of Ubuntu (3 times)
3. Minimization of hard drive space
4. Working on an OS - ran into some bugs with the file system (Everything else working great ).
5. Lack of time on the computer
6. Reading old planet zebeth comics - w00t! Go mature humor in retro games!
7. Packing, moving, destroying furniture
8. Some other C++ projects
9. I just felt like adding a ninth reason, that's it really


ALSO, I'm probably going to change the tutorial "style" from showing source code at the end, to showing it where-ever I reference it (Or, rather, a mix between that system and the current one).

SOURCE CODE 1-4


MAJOR NOTE!!! - R E A D M E ! ! !
I uninstalled DBPro to free up space... (I still have the disc though). Looks like a tutorial won't be out until I either a) get a new computer, b) get a larger hard drive, or c) reinstall DBPro (If I have enough space for it). Oops?


Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.

Attachments

Login to view attachments
Sasuke
16
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 14th Nov 2008 02:30
Sweet, Aaron's back baby!

This great stuff, gimme a sec to digest this.

Side Note: I was board the other day and decided to recreate the GUI of any device around me, the first was the PSP XMB GUI. Quickly coded this so it's not refined one bit, tons need editing and adding, more varibles need to be define but you get the gist:



A dream is a fantasy, if you achieve that fantasy it was never a dream to begin with.
Omen
16
Years of Service
User Offline
Joined: 7th Nov 2006
Location: Maple Grove, MN US
Posted: 15th Nov 2008 17:37
Great stuff as always Aaron, very well-organized with good explanations

Doz
14
Years of Service
User Offline
Joined: 16th Apr 2008
Location:
Posted: 19th Nov 2008 18:20
So I seem to be having a little problem running these examples. I've never worked with dlls in DBPro so I'm pretty sure I'm missing something simple but when I try to compile it snags on the line

Init Advanced 2D

I got the dll from the post above and just put it in the projects folder, I'm guessing this is not correct or its not everything required to get this to run.

If anyone could help I would appreciate it. So far, just reading through this has been very informational, I can't wait to actually see it in action. Thanks!
GIDustin
14
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 19th Nov 2008 19:26 Edited at: 19th Nov 2008 19:27
@ Doz

Your post hasn't appeared yet but to answer your question the Advanced2D.dll goes in your "Dark Basic Professional\Compiler\plugins-user" folder.
Aaron Miller
16
Years of Service
User Offline
Joined: 25th Feb 2006
Playing: osu!
Posted: 20th Nov 2008 20:38
GIDustin is correct, you must place the DLL in the [DBP Install Dir]\Compiler\plugins-user folder. So the actual path's name might be something like: "C:\Program Files\The Game Creators\Dark Basic Professional\Compiler\plugins-user\Advanced2D.dll"

For me, my path was actually: "K:\p\The Game Creators\Dark Basic Professional\Compiler\plugins-user\Advanced2D.dll"

I hope that helps.

Cheers,

-naota

I'm not a dictator to those that do stuff for me by will. Only those who don't.

Login to post a reply

Server time is: 2022-12-01 10:37:19
Your offset time is: 2022-12-01 10:37:19