A method for returning two values from a function...
Displaying 1-20 of 24 total.
12 next
Please enter a numerical value for the importance of this sticky.
Enter 0 to unsticky.
zenogais

I've been programming verge for a little while, and I recently needed a way to return two variables from a function in order for the function to have any use. I've been a C/C++ programmer for a few years now, doing alot of low-level hardware related work, so I use bitshifts quite often. Anyway, I came up with a method for returning two values from a function inside of a bit-packed integer. The only catch for this function being that the integers have a range of 0 to 65535 as the sign-bit becomes irrelevant. Here's the code for doing, and hopefully someone out there can find this useful:


/// 2-Dimensional vector structure
struct CVector2D
{
int magnitude;
int x;
int y;
}

...

// Returns The Lowest 16-bits, in this case the X coordinate.
int GetLow(int bitPackedValue)
{
return (bitPackedValue & 65535);
}

// Returns The Highest 16-bits, in this case the Y coordinate.
int GetHigh(int bitPackedValue)
{
int ret = bitPackedValue;
ret = ret >> 16;
ret = ret & 65535;
return (ret);
}

int Add_Vector2D(int x1, int y1, int x2, int y2)
{
x1 += x2;
y1 += y2;
log("add - x1: " + str(x1));
log("add - y1: " + str(y1));

int packed = y1;
// Shift Y value into high 16-bits
packed = packed << 16;
// Add In X Value to low 16-bits
packed = packed | x1;

return (packed);
}


Now you can use this something like this:


CVector2D v1;
CVector2D v2;


void autoexec() {
// Set Initial Vector Type Values
v1.x = 15;
v1.y = 15;
v2.x = 15;
v2.y = 15;

// Perform Vector Addition
int packedCoords = Add_Vector2D(v1.x, v1.y, v2.x, v2.y);
int x = GetLow(packedCoords);
int y = GetHigh(packedCoords);

// log it to make sure it worked
log("x coordinate: " + str(x) + " y coordinate: " + str(y));
}


I'm currently trying to find a method of preserving the sign-bit, though this would decrease the maximum value of the variable, but allow the return of signed integers as well.

Posted on 2004-07-18 22:25:37 (last edited on 2004-07-18 23:40:13)

RageCage

Fancy

Posted on 2004-07-19 00:02:05

Gayo

It seems like it would be easier to just pass a pointer to a couple of quads or something.

Posted on 2004-07-19 00:47:23

Zip

Or have a couple of global ints to dump values into.

Zip

Posted on 2004-07-19 00:56:47

zenogais

The global thing probably would be easier. Gayo: I wasn't aware that Verge3 had the ability to use pointers, could you expand on that concept for a newb like myself?

Posted on 2004-07-19 01:01:43

Zip

Verge does have some DMA functionality, Gayo was refering to that. I think the docs are actually helpful on that front.

Zip

Posted on 2004-07-19 03:04:07

zenogais

Yeh, I've pretty much read through the entire doc. I suppose that could work, I might try formulating a system using that and possibly post results if I'm successful. DMA would allow me to keep signs and such as well, thanks for the information and ideas :)

Posted on 2004-07-19 05:25:57

mcgrue

DMA in verge is powerful and useful for anyone extremely experienced with ASM and C and the such, but it is exceptionally verbose to set up.

Not to mention that you cannot make references to structs, so you basically have to constuct your own structs longhand by making a dma 'object' constructor and destructor functions.

However, it's pretty much the only road to go if you're interested in making dynamically alllocated data structures or the such.

Posted on 2004-07-19 06:20:16

zaril

object MakeFunctionsReturnStructsPlease(int a, int b)

{
PreMadeStruct Please;
Please.a = a;
Please.b = b;
return Please;
}

PreMadeStruct YourMom = (PreMadeStruct)MakeFunctionsReturnStructsPlease(1, 2);


It would be creamy, admit it.

Posted on 2004-07-19 10:57:30 (last edited on 2004-07-19 10:57:50)

mcgrue

It would be a goodness of great magnitude. However... I doubt that's in the cards at present.

Posted on 2004-07-19 12:07:44

Gayo

Actually, Zip's idea is better than mine -- just have two "returnedvalue" globals and set them inside functions. Could get messy to debug, but it'd be way easier than DMA and would allow full integer range.

Posted on 2004-07-19 18:22:50

Omni

The above is a really neat experiment, but it doesn't effectively return two variables, just put them in a package from which two separate values must be extracted one by one. You end up using three functions for two values, rather than use one function to return two values.

DMA doesn't seem too hard to understand. Check the
Atrevida PC Game Programming Tutorials.


And if you already had this down, pay no attention to me.

Otherwise, yeah, the global variables that act as container for return values is good.

EDIT: However, if it works fine for what you need it to do, then take no offense from me.

Posted on 2004-07-20 02:16:07 (last edited on 2004-07-20 02:17:24)

zenogais

Couldn't agree more with you Omni, its a neat experiment but really I didn't plan on really using it. I've actually switched to DMA mode for now, but as you guys said the syntax is quite verbose, and so I won't post the code here. I wrote encapsulation functions for reading/writing bytes,words of data, both signed and unsigned from the DMA memory, I also wrote functions to add two vectors given their offsets in DMA memory. Also, Zaril, why not have functions take structs as data types:


struct Blah
{
int x;
int y;
}

int AddTwoBlahs(Blah blah1, Blah blah2)
{
blah1.x += blah2.x;
blah1.y += blah2.y;
}


Though as mcgrue stated, thats probably not gonna happen any time soon. Also a quick off-topic question to the VERGE3 developers, did you guys write your own parser, because if so I would also recommend you check out the Spirit(http://spirit.sourceforge.net/) parser that is part of the Boost library, I've used it countless times as it makes parsing most data formats a breeze.

Posted on 2004-07-20 05:16:52 (last edited on 2004-07-20 05:20:57)

Zip

I don't get this desire to pass structs, at the moment there's no a single instance you would need to. zaril's example is bad practice - if we were in a proper language you'd be creating a whole new object, the having to call the copy constructor to pass it. What you'd actually want to do is:
void NoNeedToReturnStructs(object &an_object, int a, int b)

{
an_object.a = a;
an_object.b = b;
}

PreMadeStruct YourDad;
NoNeedToReturnStructs(&YourDad, 1, 2);

No whenever you think you want to do a reference pass in verge, just use a global, and it's pretty much the same thing, you just lose a little of the protection from stupid mistakes, as Gayo pointed out above.
Seeing as all structs MUST be global anyway, and one function is only ever going to be dealing with one kind of stuct (no classes kids, don't try to fake it), there is no reason just to pass the index of a struct array around.
void StillNoNeedToReturnStructs(int index, int a, int b)

{
YourSisters[index].a = a;
YourSisters[index].b = b;
}

PreMadeStruct YourSisters[3];
StillNoNeedToReturnStructs(0, 1, 2);
StillNoNeedToReturnStructs(1, 24, 12);
StillNoNeedToReturnStructs(2, 4, 8);

Happy now?

Zip

Posted on 2004-07-20 12:52:05

Gayo

It's just that passing the index is kind of a pain. It's not one of the worst deficiencies in that there's an easy workaround, but it is a mite painful.

I should note that it's incredibly valuable to be able to pass by reference for integers, too, since there isn't any workaround for that.

Posted on 2004-07-20 15:24:46 (last edited on 2004-07-20 15:27:09)

mcgrue

Zeno, yes, vc is a custom parser and interpreter. I don't think vecna's interested in this time in ripping it out and replacing it with something 3rd party.

Posted on 2004-07-20 15:26:24

Gayo

What we need is for someone to make an executable that parses upper-level custom preproc things in code, then outputs a vc file, then calls VERGE to compile that. :D

Posted on 2004-07-20 15:28:16

Zip

Quote:Originally posted by Gayo

It's just that passing the index is kind of a pain. It's not one of the worst deficiencies in that there's an easy workaround, but it is a mite painful.


Passing an int is a damn sight more efficient than creating a new object, copying it to return, then destorying the first one, which is what zaril's code would do.

ANY time you think you need references in verge, just use globals - you lose a bit of free memory and some error detection, but it's really not a big problem. As for you second suggestion Gayo, it would be easier to start from scratch in c++ and use a library for the graphics stuff.

Zip

Posted on 2004-07-20 16:13:48

zenogais

McGrue: Wasn't expecting you guys to actually change to Spirit, but just a suggestion.

As for VERGE-C its alot like C, as has probably been stated countless times, I personally don't mind using alot of globals, its just something new I've got to adjust to as in my C++ code I rarely if ever use a global variable. Also that reference passing code isn't quite right above, you're passing a pointer into a function that takes a reference, the correct way would be more like:


PreMadeStruct YourDad;
NoNeedToReturnStructs(YourDad, 1, 2);


Thats what made C++ references so powerful, you didn't have to convert it into a pointer, you just passed the variable in and the compiler generated all the code needed to make it like you were passing a pointer. I like VERGE-C though, its a nice change from what I'm used to.

Posted on 2004-07-20 19:27:23

Zip

Yeah, my slip, shouldn't be a & there, but I think you can forgive me for not testing that bit of code first. ;)

Zip

Posted on 2004-07-20 19:36:02


Displaying 1-20 of 24 total.
12 next
 
Newest messages

Ben McGraw's lovingly crafted this website from scratch for years.
It's a lot prettier this go around because of Jon Wofford.
Verge-rpg.com is a member of the lunarnet irc network, and would like to take this opportunity to remind you that regardless how babies taste, it is wrong to eat them.