Hi, I had some time to kill and realized there are very few tutorials that cover stuff like real-time object manipulation. I hope this helps you understand it

.
Memblocks, Images, and Objects
by BMacZero
To those not in the know, memblocks can be downright scary. However, they are invaluable tools for creating and manipulating media in-game, a must-have for many projects.
As their full name,
memory blocks, might indicate, memblocks are really just a long line of bytes (a byte being a little block holding a number between 0 and 255 in the computer's memory). Once you learn the significance behind the
order of the bytes, manipulating a memblock is no harder than manipulating an array.
Naturally, you can create your own memblocks for storage purposes with the MAKE MEMBLOCK command, but for this tutorial I'll focus on making and manipulating objects and images. You should be able to figure out how to do that on your own with this information, should you need to.
Images
So let's say you've got an image, and you need to modify it in some way during the running of your program. For example, in a Space Invaders game, one would have to dynamically blast a hole in the bunkers whenever they got shot:
You might first try to paste the image into a bitmap, draw on it with the DOT or LINE commands, and then use GET IMAGE to store it as an image again. The problem with this is that GET IMAGE is
slow. We can do this much more quickly by making the image into a memblock and manipulating it directly in the memory.
First, you use the MAKE MEMBLOCK FROM IMAGE command to make a memblock with all of the image data in it.
This data is formatted simply. The first four bytes, or one
dword, tell the image width. The next dword tells the image height, and the third one gives its color depth. Width and height should be self-explanatory. The Color Depth describes the number of
bits of information there are about each pixel in the image. This will generally be a power of two. There are 8 bits in a byte, and four bytes in a dword.
Almost every image you deal with will be a standard RGB image with color depth 32 - one byte each for the Red, Green, Blue, and Alpha components of the pixel (Alpha is the amount of transparency). The following illustration of a color depth 32 image as a memblock may help:
Yes, that's right, the bytes are in reverse order from the RGB configuration you're used to - BGR. Don't get tripped up! The color information is stored pixel-by-pixel, working from the top-left pixel across the first row, then the second row, then the third...all the way to the end. Just like reading this tutorial. It's easy, honest!
As an example of how you would use and manipulate this info, here is a cleaned-up snippet from my Space Invaders code. This is what the code does after it has determined that a bullet has entered the area occupied by one of the bunker sprites.
`Make the memblock
make memblock from image 1,12+e
`Get the image dimensions and memblock size for later use
imageWidth=memblock dword(1,0)
imageHeight=memblock dword(1,4)
memSize=get memblock size(1)
`Calculate the position of the bullet relative to the image
`isx(c) and isy(c) are the coordinates of the bullet on the screen itself
bulletOffX=isx(c)-sprite x(150+e)
bulletOffY=isy(c)-sprite y(150+e)
`This calculates the position within the memblock data of the pixel the bullet is colliding with
`We add together all the data that comes before it: three dwords for the width, height, and depth, a dword for each pixel from
` the left side of the image, and finally a number of dwords for the rows above it.
`Now I multiply the number of dwords we just found by four, because memblock locations are measured in bytes, not dwords.
`Finally, I have the position of that pixel within the memblock.
t=(3+bulletOffX+bulletOffY*imageWidth)*4
`Make sure this position is actually inside the image data
if t<memSize
`Check to see if that pixel is actually part of the bunker image or if it's just blank space
`After all, it would be silly if the bullet exploded against an empty part of the bunker that had already been blown up
`I add 1 to the position we found earlier because the bunkers happen to be green (RGB 0,255,0), so I want to check
` against the green byte of the pixel
if memblock byte(1,t+1)>0
`I loaded in an explosion graphic at the beginning of the code
`That graphic is stored in memblock 2. It is exactly 8x8 pixels
`In this code, I go through an 8-by-8 block in the bunker memblock, centered on the bullet impact location. If the
` pixel in the explosion image is filled, I make the corresponding pixel in the 8-by-8 block black.
`This creates a realistically blast-shaped hole in the bunker image
for x=0 to 7
for y=0 to 7
`First we check if the pixel in the explosion image is filled, otherwise we don't need to modify its corresponding
` pixel on the bunker.
`We also make sure that the pixel actually lies inside the boundaries of the 2-dimensional image, otherwise
` the explosion will wrap around (so if the bunker go shot on the left side, half of the blast would appear
` there and the other half on the right side).
if memblock byte(2,(3+x+y*8)*4)>0 and x+bulletOffX<24 and x+bulletOffX>3
`Finding the position of this pixel in the memblock...again
t=(3+(bulletOffX+x-4)+(bulletOffY+y-4)*imageWidth)*4
`And finally blanking out this pixel by writing the dword value for black (0)
`(After we make sure one last time that the pixel is within the memblock boundaries)
if t>11 and t<get memblock size(1) then write memblock dword 1,t,0
endif
next y
next x
endif
endif
`Finally, we delete the old image, create a new one in its place using the memblock data, and delete the memblock
delete image 12+e
make image from memblock 12+e,1
delete memblock 1
You might have got from the code above that one of the most annoying parts of working with images in memblocks is figuring out the position of a pixel within the memblock. In my opinion, you'd be right. We're storing 2 dimensions of data in 1 dimension of storage - it's gonna get ugly. Just work carefully and make sure you do it right the first time - it's a pain to debug. Remember that the memblock bytes start at number 0 and end at
one less than the memblock's size, because the zero term counts, unlike in arrays.
Get it, got it, good? See if you can make a program that loads an image and allows the user to scribble lines on it with the mouse, using memblocks of course

.
Objects
Tired yet? Reading this isn't as much work as writing it, I guess. Well, on to object manipulation! Memblocks for objects are much more complicated in many ways (they're 3-dimensional, so that's to be expected), but also less complicated in some. One of the reasons they are
less complicated is that instead of storing data on each and every pixel by location like we have to do with images, we just store the coordinates of each vertex in the object and how they connect. One of the reasons they are
more complicated is that there are a lot of different ways this information can be stored. With images, the color depth tells you how many bits deal with each pixel, and that's that. But with objects, each vertex can have coordinates, normals, diffuse colors, and even more. An FVF (flexible vertex format) number tells you how all this is stored (you can read
this for more information on different FVF formats, but you won't need to for this tutorial).
Before I proceed, I will point out that while memblock
can be used to manipulate objects, they aren't always the best way. Often, you'll want to use the vertexdata commands if you are manipulating an object during the execution of your program. They are faster when simply manipulating, but if you needed to add or remove vertices from a mesh, you would have to create a suitable mesh and add it with ADD MESH TO VERTEXDATA, then manipulate the added vertices so they go where you want - a memblock, however, can easily be copied to one of a different size, and more vertices added.
So, you have an object. You make it into a mesh with MAKE MESH FROM OBJECT, and then make your memblock with MAKE MEMBLOCK FROM MESH (you can't go straight from object to memblock). Most objects you load into DarkBASIC should be FVF 274 (not 338 like the help files say). The memblock data for a mesh with this format looks like this:
Explain, you say. Okay - the first dword in the memblock is the object's FVF. The second dword is the number of bytes of information that belong to each vertex. For example, if each vertex had only its location, each vertex would take up three dwords, or 12 bytes, and this number would be 12. The third dword is the total number of vertices in the mesh.
Let's look at the second dword. For FVF 274, this number should be 32. So, 8 floats or dwords per vertex (a float is 4 bytes, same as a dword, but the object data uses floats instead of dwords for some data because they can store decimals). These happen to be (in order): the float x, y, and z positions of the vertex relative to the object's center, the float x, y, and z components of the normal vector for that vertex, and the float u and v coordinates of the vertex on the object's texture. The normal of the vertex should be thought of as the direction it points - usually away from the object. This is used in calculating lighting. Notes that the u and v coordinates are actually proportions between 0.0 and 1.0, not pixel coordinates. For example, if a vertex had u 0.5 v 0.5, and the object was textured with a 512 by 512 texture, that vertex would lie on the 256,256 pixel on the texture.
How does DBP know which vertices connect to form faces? Every consecutive set of three vertices in the data form a triangle. This means that one vertex may appear many times in the data if it serves as a corner to a number of polygons.
So, another example (this one is from one of my DBP Coding Challenge
entries). In this code, I'm using a combination of sine and cosine waves to simulate an ocean on a flat, gridlike mesh (in an ocean wave, each particle actually moves in a circle, not just up and down in a sine pattern).
inc angleoff,wavespeed
if angleoff>=360 then dec angleoff,360
`In this example, I'm just going to step through every vertex in the mesh and reposition it based on its
`Memblock 2 contains the current shape of the ocean
`Memblock 1 contains the original flat grid
`Because a new vertex occurs every 32 bytes, the step command will make it easy to find one vertex at a time.
`(I start at 12 because of the three dwords of data at the beginning, which I don't care about right now)
for c=12 to get memblock size(1)-1 step 32
`Calculate the new position of this vertex based on its starting position
`This causes the vertex to move in a circle over time
tempx# = memblock float(1,c)
tempy# = memblock float(1,c+4) + sin( angleoff + wavelength*memblock float(1,c+8) )*amplitude
tempz# = memblock float(1,c+8) + cos( angleoff + wavelength*memblock float(1,c+8) )
`Write the new positions we calculated to the memblock
`We don't need to write the x position because the waves don't move in that direction.
write memblock float 2,c+4,tempy#
write memblock float 2,c+8,tempz#
`Adjust the normals to point out of the surface of the water
`Using good ol' geometry - this is the inverse reciprocal of the offset vector
write memblock float 2,c+16,tempz#
write memblock float 2,c+20,-tempy#
next c
`Make the display object from the updated memblock data
make mesh from memblock 1,2
delete object 1
make object 1,1,1
delete mesh 1
I didn't follow my own advice in this one, and used memblocks to just manipulate the mesh. I tested it against a similar entry by Kira Vakaan using the vertexdata commands and found them to be far faster. But this is good for teaching purposes.
Questions or comments?