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.

DarkBASIC Professional Discussion / Memblock tutorial [updated 30-12-11]

Author
Message
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 26th Dec 2011 21:46 Edited at: 30th Dec 2011 20:11
Hi guys, I'm in the process of scripting a memblock tutorial for my usual DarkBASIC Professional video's but I might be a little shaky in my understanding of them because I've never needed to use them in any of my own projects so far. So rather than just blindly producing a video that turns out to be mostly wrong, I thought I'd post a draft of the opening script here.

Feel free to point out all the bits it I got wrong!

********* Script v0.6 *******

Memblocks


Because I’m going to be wrapping up any DarkBASIC Professional tutorials for the next six months, in preparation for DarkPRINCIPLES 2.0, I thought it was about time I tackled the tricky subject of memblocks.

So first of all, what is a memblock and why is it useful?

A memblock, simply put. Is a block of memory used to store some kind of data. In many ways it’s like using an array, or creating an identifier in that it’s purpose is to hold some kind of information in memory. While identifiers and arrays have a very structured way of doing this, memblocks give complete freedom to the user by allowing direct access to raw information. You could for instance create model data in a memblock and then export that data as a .x file. You can create or manipulate image files, or even produce sounds. You can send network data using memblocks, or even create your own unique file format. A boon to any user worried about anyone ripping their content from their games. A memblock is completely freeform, but it does require one thing. Knowledge of the data structure in question. You can’t put any old mess into a memblock or the computer simply will not know what to do with it no matter what file extension you save it with. If you do decide to create your own file format, then it’s simply a matter of instructing the computer on how to understand it. DarkBASIC Professional has memblock specific commands that help with all of this, and make your life much easier if you are happy with standard formats. But this is all pretty advanced stuff, and for now we’re just going to look at the basics. Namely how to get data into a memblock, and how to pull data out of it.

So how does memory work?

As we all should know, computer technology is based on the humble bit. A bit is a simple switch with an on or off state. This is what we call binary data. The computers memory is formed into groups of 8 bits, which we call bytes. Every byte is indexed by a 32-bit memory address. These memory addresses simply count up from 0 to whatever until there not more memory to access.

In theory we can at any time write to any memory location on your computer, but in real life you can’t do this. Windows, as well as it’s applications and services are already using a whole heap of memory, so if the user was allowed to simply address memory directly there would be no knowing what trouble they could get themselves in. So, this is why we create memblocks. By creating a memblock, we isolate a block of memory, and tell windows to reserve that block for our usage. By doing it this way, we don’t interfere with windows nor it’s services, processes or applications.

Pointers

So what are pointers and how do they work? Pointers work as memory location references. That is, they store the specific 32-bit memory address that the data is held at. But they don’t only do this, if you put an astrix in front of a pointer then that pointer is deferenced and instead accesses the data stored at that memory location. Because memory addresses are always 32-bit, any pointer created must be assigned as a DWORD. A DWORD has the numerical range of 0 to 4,294,967,295 so there can never be any addresses that exceed that number. It also can’t handle negative numbers. Because DarkBASIC Professional and indeed most operating systems are 32-bit this does limit the amount of ram you can access. But for the majority of software, this is more than enough.
The basic memblock commands

Before we can use pointers, we need to reserve a block of memory for our usage. To do this we use the Make memblock command. The make memblock command works in the usual DarkBASIC Professional way. You assign a memblock ID, and a size.

MAKE MEMBLOCK memblock number, size

The memblock number references the memblock you created, this allows DarkBASIC Professional to manage memory addresses for you and it allows you to reference those memory addresses when you need them. Please note that you can only create 255 memblocks at any one time, though I doubt you’ll ever need more than two or three at any on time.

Size is fairly straight forward, it’s managed in bytes, so a vaule of 1 equates to a value of 1 byte, if you put in 256 bytes then you get 256 bytes which is a lot of data.

This command will create the memblock but you also need to retrieve data from that memblock, and to do this we’re going to use the GET MEMBLOCK PTR command. This command passes a the memblocks address into our pointer value as an integer.

The practical bit

Now lets create a simple program that will create a memblock, retrieve that memblocks memory address, pass data into that memblock and then display both that memblocks address and it’s data.

We start off by creating a varible called pointer, and assigning it as a DWORD.

pointer as DWORD
Next we create a memblock and assign it the ID of 1, and a value of 1 byte.



Now we get the memory address from that memblock we just created and pass that value into pointer.



Next, using the atrix, before the varibles identifier, we deregister that pointer and pass our programs value into memory.



Now we call a couple of print statements to display both the memory addresses value (note, this will chance will every running of the program) and reference the data within the pointer.



Finally we use wait key to pause our program.



The complete code



Some more theory about memblocks

So far in this tutorial, we’ve simply grabbed a memory location and written data to it using pointers. Now we’re going to do the same thing using memblocks. With pointers we can store virtually any kind of numerical data we like. We don’t have to worry about the size of the value we put into it. Memblocks are far stricter so you’ll need to understand the differences between the four types of data you can use.

Byte, as specified before is 8 bits, in binary the way a bit works is by adding together different combinations of bits to form a value. For example:

00000000 = 0
00000001 = 1
00000010 = 2
00000100 = 4
00001000 = 8
00010000 = 16
00100000 = 32
01000000 = 64
10000000 = 128

By adding additional 1’s into the sequence we can make any number for example, the maximum value possible in a byte is:

11111111 = 255

if I wanted to represent 129 then it would be 10000001
10000010 = 130
10000011 = 131 etc

The upshot of all this, is that the maximum value you can placed into a single byte is 255, if you exceed that number than you will get an error saying:

“Runtime error 5105 - Memblock position outside range at line x”

what this means is that you’ve attempted to put something larger than a byte into a memblock that’s not big enough to support it.

The next size up from a Byte is a WORD. A word works in the same way as a byte, except it supports much larger numbers. In the same way a byte works in a sequence of 1 2 4 8 16 32 64 128 a WORD adds another 8 bits, so we’re moving from 8-bit to 16 bit, this gives us 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 which gives us a maximum possible number of 65535.

The next size up is a DWORD which follows the same pattern and allows for a maximum size of 4294967295

Finally there’s the Float which is a 32-bit value. However you can only write a float value with eight decimal places if you wish that float to remain accurate. For example. 0.999999 will remain accurate, while an extra 9 will cause the program to round it off at 1. If you lose a 9 off the end, you can also have 9.99999 or you can have 99.9999 or 999.999 I’m sure you see the pattern here. As you move the decimal point backwards or forwards, you lose from one end and gain on the other.

What this all means is that, to host a byte you only need 1 BYTE created in your memblock, to host a WORD you need two bytes, to host a DWORD you need four bytes and for a FLOAT you also need four bytes.

Read and write memblocks

Now that you understand the different types of data we can use lets have a look at the memblock commands. The first command we’ll need is write memblock which comes in four flavours.

Write Memblock Byte Memblock ID, Position, Data
Write Memblock Word Memblock ID, Position, Data
Write Memblock Dword Memblock ID, Position, Data
Write Memblock Float Memblock ID, Position, Data

Each of these commands work in exactly the same way, only the nature of the data changes which was covered above. The first parameters, memblock ID refers to the memblock number you created, the position refers the the byte’s position. In the same way arrays do, memblocks start at 0, so if you create a memblock with the size of 1 byte, then it’s position will be 0.

The next commands are:

Memblock Byte(memblock ID, position)
Memblock Word(memblock ID, position)
Memblock Dword(memblock ID, position)
Memblock Float(memblock ID, position)

To use these commands just pass them into a varible for example.

MyByte = Memblock(1, 0)
MyFloat# = Memblock(1, 0)

etc. This command simply retrives the data, in the specified format and passes it into an identifier.

Writing and reading memblocks practical code

We need to assign our tmpdw as a DWORD or it will simply reference as an integer, and cycle to 0 rather than giving the correct number.



First we start our practical program off by creating a series of memblocks, remember that bytes require 1 byte, Word requires two bytes, dword requires four bytes and floats require four bytes as well.



Next we write the maximum data values we can to each of our created memblocks. We’re keeping this example simple and writing four different memblocks rather than mixing the data into one big one.



Now we’re going to take the data we just placed into our memblocks and pass them into identifiers ready to display on the screen.



We finish up our program by printing the results of each, and waiting for the user to press a key to end the program.



Complete code:


Combining all this data into one single memblock.

In the last example we used four seperate memblocks, now we’re going to store all this information in one single memblock. To do this we need to work out the positions within that memblock based on size and previous data stored. We’ll do it in the same order, a byte, a word, a dword and finally and integer, so that means we need:

1 byte = byte
3 bytes = byte + word
7 bytes = byte + word + dword
11 bytes = byte + word + dword + float

So instead of simply using Make memblock 1, 1 we instead create a memblock with 11 bytes in it.

Now we need to consider the starting position of those bytes. We already know that memblocks work in the same way as arrays in that they start at a position of 0. So that means, our first byte starts at 0. Then we add the size of the preceeding byte, to get the next slot.

byte = 0, word = 1, dword = 3 and float = 7.

So now that we’ve worked out the position of this data within our memblock we can simply save and load the information into memory at will.

Final practical bit, combining the data into one memblock

This program largely follows the previous version, with one key difference. Everything now refers to memblock one. Two three and four are removed completely from our program and instead we use the postion information we just worked out to place and store our data. In the same way we did before we’re opening with tmptw as DWORD so we get the right value printed.



Now we create our single memblock with 11 byte’s.



Next we write the same data as before, using positions instead of different memblocks. We’re using the positions we worked out just now.



Finally we call the memblock data into identifiers, and use the position of the memblock rather than referencing several different memblocks.



And finally we print the results for testing and wait for the user to press their key.



Memblock and bitmaps

Now we have the basic in’s and out’s of memblocks we can start to do something more interesting, up until now we’ve just been placing data into a memblock and and taking data out of it. But what if we wanted to create an image using a memblock instead?

As I previously stated, before you can do something like this you need to understand how the data is formatted, for this example we will be working directly with bitmaps so the data is formated like this.

byte 0 to 3 = bitmap width
byte 4 to 7 = bitmap height
byte 8 to 11 = bit depth
byte 12 to ∞ = pixel data

Everything here is a DWORD so you need to allow four bytes of data for each entry including the pixel data.

The width, height and bit depth is pretty self explanatory. With a little bit of math we won’t even need to know our projects bitmap dimensions for this program to work. The art of good programming is allowing the computer to do all the work for you.

The pixel data is easy to manipulate, in fact you can use the rgb() command to do so, for example, WRITE MEMBLOCK DWORD 1, 12, RGB(255, 255, 255) will create a white pixel in our memblock. It’s as easy as that. It gets a little tricker if you want to position your pixel data precisely, for this we need a little bit of mathematics but again it’s straight forward enough.

The sum I use comes in two parts, because we’re working with X and Y, we’ll do this in two parts. First, we need to work out the y position on the screen. This is done with.

y = (pixel you desire)
y = y * width * 4 + 12

The y represents how far down the screen you want to go, but to get there we need to multiply it by the number of pixels from left to right, and then multiply it by four. Remember each pixel location is a dword, so that’s four bytes, we add an addition 12 to compensate for the first 12 pixels discribing the images settings.

Imagine you’re using a word processor, and for some reason the return key is broken. To get to the next line, you have to press space until your cursor appears on the next line, the same thing is happening here, we’re simply skipping the memory locations we don’t want to adjust, until we hit the line we desire. This is the Y axis.
The next part is to add the X axis to the sum, this is easy enough, it’s simply as follows.

X = (x location)
X = X * 4

And that’s it for the X axis, now all we do is add them togther to get the memory location we wish to alter.

(y * width * 4) + (x * 4) + 12

And there we have it, our memory location.

A simple drawing program

Now you know how to find the correct pixel within the memblock and update it, we can proceed onto our program. But before we do lets go over it’s structure.

First we’re going to start by producing a memblock from an existing bitmap, DarkBASIC Professional provides this for you readily, and at the size and bit depth of your programs viewing area. So if you create a program that’s 640 x 480 x 32-bit then that’s the bitmap that’s automatically generated. We do this with the MAKE MEMBLOCK FROM BITMAP command, this basically imports the background as a bitmap into a memblock giving you an image file in memory ready to edit.

Next we’re going to extract the width, height and bit depth from the created memblock, and bring it into our program as a set of variables. Once this basic data has been imported we move onto the main bit of our program.

For our main loop, we’re going to take the mouses location, and draw a dot at that location when the left, middle or right mouse button are pressed. Left will produce a nice cyan colour, the middle yellow and right purple.

Once per cycle we will then convert our memblock back to the bitmap which will then update the background so the user can view their art.

The art program

We start our program by using the existing bitmap backdrop and converting it into a memblock ready for us to edit.



Next we extract the data from our bitmap ready to use, but bit value won’t be used in this program, but it’s useful data to know how to extract so I’ll leave it in there just for reference.



Next we start our do and loop sequence, there’s no need for sync with this example, when we update the bitmap we update the screen’s background.



This part of the program will basically be repeated three times with different colour settings and different mouse buttons. But the math and logic are the same throughout. We start by asking if the left mouse button has been pressed.



If it has, then we need to get the mouse pointer’s location, and assign it to the value of X and Y using our previously discussed mathematics. There’s no need to compensate for the 12 extra bytes here, because we’ll do that in the memblock command instead.



So now we have the raw data sorted, we then need to bring it into our memblock command.



And finally we end the if statement.



Now lets repeat the process for our two other buttons, 2 is the right mouse button and 3 is the middle. I’m using a wheel mouse, so I’m clicking that instead. This means I map that button to 4 instead of three.



Now that we have our memblock data entered and ready to use, we then convert it from a bitmap into a memblock, this automatically updates the screen for us allowing us to view our masterpeices.



And finally we loop the program and repeat these actions.


The complete code



Some other interesting things you can do with memblock images


Parallax starfield

While our art program was very pretty, we can also produce pre-prepared images using memblocks, using the function we just created. This parallax starfield example will produced a “layered” starfield, were more distant stars are darker in colour and closer stars are brighter. I will do this So we’re going to start this program off by defining the globals.



Now we assign our globals and create our memblock



Next we draw our starfield by starting double layered a for and loop sequence. Para controls the different “layers” of stars we produce up to 8 levels. C controls the colour of those stars, every time the para loop loops, we increase the star’s brightness by 32 units. But because the RGB range is 0 to 255 not 1 to 256 I’m also subtracting one to bring the total value within that range. Next we start drawing the starfield layer. We do this within the stars loop which we create using a randomized number that can be no less than 128 stars. I then write the memblock data using the XYConvert function. I subtract 1 from width and height, because memblocks go from 0 to whatever, this compensates for that. The rgb value is of course the colour we setup in the para loop.



Now that our stars have been drawn, we can simply create the bitmap, and end the tutorial. The rest of this program we’ve already gone over, so you’ll now how it all works.



Complete code


Fractal flower

This is a code snippet I pulled from HERE and then modified to use our created function. I won’t go into the mathematics myself because that’s a whole different tutorial, but you can use this code to produce something a little more interesting than our basic art program using the memblock’s function we’ve already created, and by replacing the dot command with it.

The complete code

SoftMotion3D
AGK Developer
18
Years of Service
User Offline
Joined: 24th Aug 2005
Location: Calgary,Alberta
Posted: 26th Dec 2011 22:49 Edited at: 26th Dec 2011 22:57
Quote: "You could for instance create model data in a memblock and then export that data as a .x file."

maby if you understand how the .x file needs to be written out and saved but i think you ment to say mesh. Darkbasic can dump a 3d object into a solid mesh with no limbs.

Also if it wasnt mentioned.... memblock memory access i believe is faster then array data access....

Correct me if im wrong...

Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 26th Dec 2011 23:04 Edited at: 26th Dec 2011 23:05
Noted thanks. Yes as far as I'm aware arrays are slower than memblocks.

I think I'm right in saying you can use memblocks to create a full .x file, texture locations, vertex's, etc. The whole nine yards (providing you understand the .x file's structure). But you are right meshes are the more common usage.
IanM
Retired Moderator
21
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 26th Dec 2011 23:24
You can use memblocks to represent ANY type of data - your script covers the standard DBPro media types, but you can also use them to transfer free-form data across the network using DBPro's network commands, use them to hold pre-compiled scripts (eg, byte value of 0 represents 'move-left' and is followed by a 4 byte float for distance etc).

The bit about DBPro media types requires you to stick to DBPro's own imposed structures, eg images are 4 bytes width, 4 bytes height, 4 bytes bit-depth, followed by a block of width*height*bit-depth/8 bytes representing the graphics data etc.

Also, I think that you went off-track with pointers - you should stick with just the standard memblock access commands WRITE MEMBLOCK BYTE etc.

So, I'd introduce memblocks initially with image data, then maybe branch out in later tutorials with more complex data such as objects and/or sounds, then go further with free-form formats for other uses.

That's my 2 pennys

ZestyPro
12
Years of Service
User Offline
Joined: 27th Aug 2011
Location: The Grid
Posted: 26th Dec 2011 23:37
whats funny is I was going on the forum to ask about memblocks. And I found this tutorial. Thanks for the help!

i like cheese pizza. do you like cheese pizza?
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 27th Dec 2011 01:45
Ok, I've just posted the new version. It now goes into more detail regarding memblocks. I've left the pointer's in there, they are useful to know.

See the first post for the new version, and again all comments welcome.
mr_d
DBPro Tool Maker
17
Years of Service
User Offline
Joined: 26th Mar 2007
Location: Somewhere In Australia
Posted: 27th Dec 2011 06:22
you may want to confirm your theory section as I've been taught that the binary bits of a byte are built the reverse way. i.e. instead of:
00000000 = 0
10000000 = 1
01000000 = 2
00100000 = 4
00010000 = 8
00001000 = 16
00000100 = 32
00000010 = 64
00000001 = 128
it would be:
00000000 = 0
00000001 = 1
00000010 = 2
etc.
10000000 = 128
11111111 = 255
the way you have it may apply to memblocks as they are implemented in DBP, but then the theory should still be the shown the normal way.

Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 27th Dec 2011 11:54
Yep you're right. I'll correct that now.
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 28th Dec 2011 00:22
Hi guys, I made another update. The update deals with converting bitmaps into memblocks and memblocks into bitmaps, it yets the user produce a basic art program by manipulating image data directly. It even has a whole 3 colours!

The update has been posted on the first post of this thread.
chafari
Valued Member
17
Years of Service
User Offline
Joined: 2nd May 2006
Location: Canary Islands
Posted: 28th Dec 2011 00:33
@Daniel TGC Thanks for your memblock tutorial. Just one thing....I'm an old man and sometimes I lost myself at home for those people like me...why don't you put you code like:



I'm lost


Cheers.



I'm not a grumpy grandpa
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 28th Dec 2011 00:44
Because if I just post a snippet no one will read the tutorial. I like to make people work for their knowledge, that way people don't come back asking questions I've already covered. It's not very conviniant I agree, but it annoys me when people skip the tutorial, copy the code, and then ask me questions that I answer in the tutorial. It's happened so many times over the last four years, I've given up making things too easy for people.
chafari
Valued Member
17
Years of Service
User Offline
Joined: 2nd May 2006
Location: Canary Islands
Posted: 28th Dec 2011 00:53
Ok I apologize ...I know what you mean ... I have been teaching people in other stuff my whole life. Thanks anyway for your answer.

Cheers.

I'm not a grumpy grandpa
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 28th Dec 2011 01:09
There's no need to apologise, it was a valid question.
Zotoaster
19
Years of Service
User Offline
Joined: 20th Dec 2004
Location: Scotland
Posted: 28th Dec 2011 02:11
Nice one Daniel. I'll just stick this into the tutorials thread in the newcomers' corner for people to refer to

"everyone forgets a semi-colon sometimes." - Phaelax
Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 28th Dec 2011 12:34
Hi guys, I did some speed tests on memblocks vs the DOT command. Come see the results HERE
MrValentine
AGK Backer
13
Years of Service
User Offline
Joined: 5th Dec 2010
Playing: FFVII
Posted: 28th Dec 2011 23:19
Wah... Yikes... started reading and did not realise how long a post it was...

I am curious as to whether anybody reads the included code examples...

Anyhoo... Daniel I have an Idea for Dark Principles 3.0 ... something which I may pay for hehe

Daniel TGC
Retired Moderator
17
Years of Service
User Offline
Joined: 19th Feb 2007
Location: TGC
Posted: 30th Dec 2011 20:15
sorry MrValentine I just made it longer with 0.6, it will get longer still by the final draft (1.0) at which point I'll turn this script into a video.

But I've taken chafari's comments onboard and sectioned off the code area's so it won't seem quite so bad. Users can skim and copy the code if they want too now.

DarkPRINCIPLES 2.0 is in development as of the first of 2012, so I think it's a little soon for 3.0! lol, but I'm happy to hear suggestions always.
MrValentine
AGK Backer
13
Years of Service
User Offline
Joined: 5th Dec 2010
Playing: FFVII
Posted: 30th Dec 2011 20:28
emailed you

Login to post a reply

Server time is: 2024-03-29 10:30:49
Your offset time is: 2024-03-29 10:30:49