Posted: 22nd Jan 2011 22:49
Arrays and me don't go well together.


That's a rather defeatest attitude

Under DBPro syntax it would look like this.
With object numbers:
+ Code Snippet
for i = 1 to 100
    load image "image_" + str$(i), i
next i

paste image 5, 0, 0


Without object numbers:
+ Code Snippet
dim images(100) as Image

for i = 1 to 100
    images(i) = load image("image_" + str$(i))
next i

paste image images(5), 0, 0


One extra line in one scenario, but you completely remove the whole issue of either remembering which numbers have been used, or finding a free one (which wastes time).

(And for those about to "cleverly" point out that I didn't use index zero in the array, I left it to refer to an invalid/non-existant image)
Posted: 22nd Jan 2011 22:50
This is what arrays are for. You can loop through them.

Remembering object numbers is very outdated and I don't know many languages that do that, except the dark basic kind. It is silly and not really needed. Arrays can do this nicely if you need to do a loop.

Edit, yep... This exactly... see how clean this is?

dim images(100) as Image

for i = 1 to 100
images(i) = load image("image_" + str$(i))
next i

paste image images(5), 0, 0
Posted: 22nd Jan 2011 23:28
I usually code like this

+ Code Snippet
Type character
  name AS STRING
  objectNumber AS INTEGER
  imageNumber AS INTEGER
  //whatever else needed
EndType

Dim character(numberOfCharacters) AS character

//and if it's so supported in the language
character[0].name = "Jerico2day"
character[0].objectNumber = loadObject(#AGK_Any, "filename")
  // where #AGK_Any constant requires the function to return the object number it so chooses
  // if you enter a constant instead, it will use that number and 
  // can return true/false depending on if it was successful
  // if you use #AGK_Any, it will return any number the compiler wants or false on failure.
character[0].imageNumber = loadImage(#AGK_Any, "filename")
textureObject(character[0].objectNumber,character[0].imageNumber)


Of course, on hand-held devices where there's very limited ram, or on projects where you fear you could use up all the ram, I'd probably choose a different coding style.

Enumerations come to mind as being particularly helpful.

+ Code Snippet
Enumerate
  #constant1
  #constant2
  #constant3
EndEnumerate

where constant1 = 0, constant2 = 1, constant3 = 2
Posted: 22nd Jan 2011 23:59
+ Code Snippet
dim images(100) as Image

for i = 1 to 100
    images(i) = load image("image_" + str$(i))
next i

paste image images(5), 0, 0


My 'issue' is not with the loading part of images (or other media). I understand how to do it. But, my point is that no matter what, you still have to number everything that you load or manipulate.
And, suppose you dim 100 images, and later on in your program, you delete 10 of them, how do you find the right image back? If you remove 10 images out of an array of 100, the others have different numbers, right? Or, am I wrong?
When you number your images in DBPro (no arrays), it is easier to keep track of the image number.

Cheers
Posted: 23rd Jan 2011 0:55
But, my point is that no matter what, you still have to number everything that you load or manipulate.


That's the whole point, you DON'T have to number everything!

Say I have a load of enemies stored in an array. Each has their own image to display. The UDT might look like this:
+ Code Snippet
type Enemy
    x as Float
    y as Float
    velocityX as Float
    velocityY as Float
    enemyImage as Image
endtype


I can then do this to create an enemy:
+ Code Snippet
... <initialize stuff>
dim enemies(0) as Enemy
enemies(0).enemyImage = LoadImage("images/someImage.png")


Then to draw an enemy:
+ Code Snippet
function DrawEnemy(e as Enemy)
    paste image e.enemyImage, e.x, e.y
endfunction


To call that function
+ Code Snippet
DrawEnemy(enemies(0))


No need for any image numbers. If I was to do that in DBPro currently, I'd have to first search through the images to find a free one, and then use that. You might say that the indices in the array are equivalent to ID numbers, but that's not true. It's perfectly safe to remove an enemy from the middle of the array without messing up all the others, as they don't depend on having a specific index in the array. Hence, new enemies can just be added at the end of the array, no need to search for a free slot.

At no point in anyone's code are ID numbers such as those in DBPro necessary. They were just invented by TGC to (supposedly) keep things simpler.
Posted: 23rd Jan 2011 1:21
That's the whole point, you DON'T have to number everything!

I think you've misunderstood my point. Whether you number an image (or anything else) with just a number, or do it thru an array, each image you create or load or manipulate gets their internal number assigned, right? How else can the interpreter know what image you refer to?
So, my point being, if you have an array of 100 images, and you delete 10 of them (i.e. numbers 7,20,31,50,57,64,70,71,80,85), what happens to the rest of the internal numbers assigned to the remaining images? Do they obtain their same internal number?
Posted: 23rd Jan 2011 1:28
No, there are no internal numbers They don't exist. They are simply an invention!

In the underlying C++ API these things are all identified using pointers (OK, so a pointer is still like a number, but it's not chosen by the programmer). These are addresses in memory where information about the resource is stored. When an image is created internally, DBPro has a big lookup table of all the image IDs against the pointers to the images, so that when you specify say 3 as an image ID, it will lookup 3 in the table, and see that it refers to an image at (say) memory address 0x15267350.

Doing it this new way, TGC can still hide the pointers and stuff from the user, but they don't have to maintain a load of lookup tables, and the user doesn't have to worry about finding free IDs.
Posted: 23rd Jan 2011 1:40
That's half the story. The other half is the effect on your DBPro housekeeping. If, for example, you

+ Code Snippet
delete image myImageArray(5)


then you need to note that myImageArray(5) no longer points to a valid image. A simple way to indicate that is to also do

+ Code Snippet
myImageArray(5) = 0


immediately after deleting the image.

You can also use another array to point to the currently free array slots in case you want to load or create another image. Same goes for objects.

It's all very straightforward and what I'd do if I needed to handle large numbers of objects or images dynamically.
Posted: 23rd Jan 2011 11:22
what happens to the rest of the internal numbers assigned to the remaining images? Do they obtain their same internal number?


Well, in my example there's still image numbers. I like having the ability to use image numbers too, I'd like both ways.

Anyway, the routine for obtaining a free image number can be done any way the developers like.

DBPro does not have a built in method of finding an unused image (or object, sound, etc) number, but matrix1utils does have functions to do this. You can also manually write functions to do it in DBPro. Before matrix1utils, what I would do is have a global that would keep track of the last used image number. Whenever I'd request a freem image, with a function called "find_free_image()", I would increment that number, check to make sure that number wasn't being used. If it was being used, I'd increment it by one and check it again. Once I find a free image number, I'd return that number. If it hit the maximum value an image number can have, it would return back to 1 and check it to see if it's free.

With this method, it's very fast as long as it doesn't run into a block of used images. If you use up all available slots, it would cause an infinate loop and crash unless you check for that too. Matrix1utils uses random numbers last I heard. It's a very fast lookup too unless you have *a lot* of images being used.
Posted: 23rd Jan 2011 13:11
We've kind of gone off-topic with this thread really.

I understand where Diggsey is coming from: my networking plug-in uses the exact same technique of returning object memory addresses to be used as handles for other commands. It works, and it's simple, but as you have to also implement a method of validating the handles you are passed, it's actually no faster than using ID's.

However, I switched to using ID's again for everything else in my plug-ins, because it fit better with the DBPro way of doing things.

Personally, I have no problem with using either method.

Anyway, if TGC continue to use numbers for ID's, I'd be happy to donate my low-memory/fast 'FreeList' class to them if they want it (and even I'll document how it works so that it can be ported from C++). I might even be able to find my DBPro prototype of it somewhere, which uses a dynamic array implementation (or write it again otherwise).
Posted: 23rd Jan 2011 13:17
You're just missing one small point If TGC implement them as a special type rather than an integer, there is no need to validate them. The user has no way to make them invalid.

+ Code Snippet
myImage as Image
myImage = LoadImage("test.png")

`This would not compile:
myImage = myImage + 1


And as an added bonus, it makes it impossible to pass an image to a bitmap command or something. The error will be caught at compile time rather than run-time.
Posted: 23rd Jan 2011 13:33
Actually I was thinking about suggesting some kind of 'resource' type, and I think that would work pretty well. Under the hood it could be a sort of dynamically allocated reference which is assigned none/null when the resource is destroyed (which naturally means that the resource has to track all references to it).
Posted: 23rd Jan 2011 13:40
@Ben,
You beat me to posting, so the this kinda follows what you've just said.

@Diggsey,
Ah, so you'd implement a handle type for each and every resource type and only allow assignment for those types and maybe for a special 'null' value?

In that case I disagree - there's still a need to validate handles. The following code is simple, but breaks without validation as it shows it's too easy to have an invalid handle:
+ Code Snippet
i as image
j as image

i = LoadImage("MyImg.bmp")
j = i

DeleteImage(i)
PasteImage(j,0,0)   ` Use of invalid handle

Or are you proposing reference-counted resources and dropping the DELETE commands for them, so that if any handle still references that resource, the resource is kept in memory?

Also, how would third-parties provide handle-types for their own plug-ins that provide resources.
Posted: 23rd Jan 2011 13:43
It would be like Benjamin said. When you delete a resource, all handles pointing to that resource are set to null/nil/nothing.

As for third party commands. It sounds to me like Tier 1 won't support third party commands as such? However, if it does, all resources could either use a common resource type, or the compiler could automatically pick up any extra resource types from plugins a bit like the DBPro compiler checks for dependencies.

At compile time they'd all get converted to the exact same thing anyway. The difference is only useful for ensuring that they are the right type at compile time.
Posted: 23rd Jan 2011 14:34
Implications of what you suggest:
- each resource has to track handles that point to it to be able to clear them when the resource is deleted.
- when a handle goes out of scope, it has to remove itself from the resource's handle list.
- when a handle gets reassigned, it's equivalent to removing itself from it's old resources handle list, and adding itself to it's new resources handle list.
- you now need a new command to check if the handle points to a resource or not.

Depending on how the handle list is defined, that's a lot of list maintenance.
Posted: 23rd Jan 2011 14:39
All of those things are already done for strings anyway, except that they are allocated and deallocated instead of added and removed from lists
Posted: 23rd Jan 2011 14:50
No they're not. Strings are not shared resources.
- When a string goes out of scope, it frees the memory it points to. No scanning of resource lists required.
- When a string is assigned to another, the old string is freed and new memory is allocated for a copy of the source string. No scanning or inserting into resource lists required.
- No special 'delete' command is required, you just assign an empty string.
- No special 'exists' command is required, you simply test against an empty string.

Strings are completely different from the resource handling in my previous post.
Posted: 23rd Jan 2011 15:00
What you do is different yes, but the triggers for those things are not. IE. it's already possible to detect when a variable goes out of scope. It's already possible to detect when a variable is reassigned. There's no need for another command to check for existance, just test it for equality against a null value.

As for speed implications:
- There's unlikely to be more assignments than commands used on a resource.
- Looking through a list of references, which probably only has one or two items in is quicker than looking up an ID in a table containing EVERY resource of that type.
- You just need a std::set<void**> per resource, which is not much overhead, and std::set automatically minimises the number of reallocations you need to do.
Posted: 23rd Jan 2011 17:36
... or you could just reference count and not store those references you have to clear at all. That's my point.

Then you can use the exact same reference-counted implementation to track sprites that use images, so that the image doesn't disappear until all user references and all engine references are dropped.

Your method means that you have sprites without images.

Sorry to say that none of your arguments so far have convinced me that your suggestion is simpler, faster or easier.

[EDIT]Stuff it, I'll code the alternatives and see what I come up with.
Posted: 23rd Jan 2011 17:53
TBH, I don't really mind which way it is done. Reference counting is perfectly fine if you think TGC will agree to that. The only problem is that certain things have a definite life-time, such as 3D objects, which could make it confusing for a beginner. I thought it was preferable to have a slightly more complicated implementation if it kept the language simpler and closer to DBPro.