Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - backspace

#1
Thanks Darmakwolf, I am sure the kids will love playing with it. I'll incorporate it into one of my edu-kits (with full kudo to you).
I have stopped my exploration into brush effects due to limited time in my curriculum, but I always refer back to enhancements on things I have touched on, such as painting, in order to re-inforce the knowledge with the thrill of applying new technology to them. So you have my sincere thanks.
#2
I also once thought that it would be really cool to have the GLBasic libraries available for a purely c++ SDK, until I discovered, it is not really needed. Everything is there already in the GLB editor. Sure c++ syntax highlighting and dot-lookups such as in Netbeans/Eclipse would be awesome. but I'm ok with Alt-Tab for references.

It take a little while to get used to the GLB data types for c++, but then you have the same thing in Java. So after a few inline tests, and getting used to the data types, I feel right at home using 100% c++ code in the GLB environment. You have to use 2 inline blocks, with a GLB function in between them, and also declare your functions in the first inline block. But once you've done it a couple of times, you do not even notice the few lines of extra code.

What's also really very handy, is the c++ output for a GLB file in c++ in the directory \Users\<user>\AppData\Local\Temp\glbasic, since is a great reference to see what the c++ commands must look like for compiling. You also pick up such functions as CGStr. If you really think about it, you use advanced data types in c++ anyway for such things as buffered strings, so it's a small step to accept the GLB data types, and you are well on your way.

Here's the default demo for the BoxPrint project redone for c++. One of my first tries. If you compare it to the GLB source, you can see that there is almost no shift in thinking between the two languages.

This is my opinion anyway. I am not saying everyone should go this route, but I am quite happy to play with the cool GLB libraries in c++, using a Basic language IDE.

Code (glbasic) Select

INLINE
//Declare functions
DGInt BoxPrint2(DGStr str_Str, DGInt x, DGInt y, DGInt wx);

DRAWRECT (300, 100, 200, 300, RGB(20,20,120));
BoxPrint2("This is a long Text, which has to be wrapped twice or thrice to fit the box", 300, 100, 200);
SHOWSCREEN();
MOUSEWAIT();
ENDINLINE

//You need an empty GLBasic function before your c++ functions
FUNCTION foo:
ENDFUNCTION

INLINE
DGInt BoxPrint2(DGStr str_Str, DGInt x, DGInt y, DGInt wx)
{
DGInt tx, ty, cx, cy, cpos;
DGStr word_Str, c_Str;
GETFONTSIZE(tx, ty);

cy = y;
str_Str = str_Str + CGStr(" ");
cx = x;

while(cpos < LEN(str_Str)){
c_Str = MID_Str(str_Str, cpos, 1);

word_Str = word_Str + c_Str;

if(c_Str == CGStr(" ")){
if(cx - x + (LEN(word_Str) - 1) * tx > wx){
cx = x; cy = cy + ty;
}//if
PRINT(word_Str, cx, cy);
cx=cx+LEN(word_Str)*tx;
word_Str="";
}//if
cpos++;
}//while
}

ENDINLINE

#3
I've solved this problem by studying the TCL example in detail.
#4
Hi there.
I know with DirectX, with c++ i can get the device context handle, and do some stuff directly in the DX screen, I am however pretty new to OpenGL, and want to know if I can get the background buffer address, widow address, or whatever is appropriate, and do something similar. Why I wish to know this, is because there are some image manipulation routines that I used in DX, and wish to do the same - if it is possible with OGL. Is this at all possible with GLBasic?
Any help in this regard will be very much appreciated.
#5
It also took me a while to figure the sqlite thing out, But once you get the hang of it, it's a great tool. There was a need for another level of wrapping in order to make it more GLBasic friendly. I've done that to make it easier for myself to use. I've included an example that has my wrapper functions. I hope you find it useful.

Code (glbasic) Select
// --------------------------------- //
// Project:      sqlite-test00
// Description:  a test of sqlite
// --------------------------------- //

GLOBAL SQL AS SQLITE     //sqllite wrapper       
GLOBAL fields$[]
DIM fields$[5]           //number of fields in database
LOCAL recordcount


DBInit("myfriends.db")   //set database name
DBSetDebug(FALSE)        //log file = GLBSqLite.debug

//Set database fields
fields$[0] = "NAME"
fields$[1] = "COUNTRY"
fields$[2] = "EMAIL"
fields$[3] = "PHONE"
fields$[4] = "BIRTHDAY"

//Drop table if it exists
DBExecute("drop table info;")

//Create table named 'info' from fields$[] array
DBCreateTable("info")

//Add friends to the database
DBExecute("insert into info (NAME, COUNTRY, EMAIL, PHONE, BIRTHDAY) values ('Abraham','Israel','abe@is.is','12345678','6 February');")
DBExecute("insert into info (NAME, COUNTRY, EMAIL, PHONE, BIRTHDAY) values ('Ivan','Ukraine','ivan@ukuks','12345678','7 February');")
DBExecute("insert into info (NAME, COUNTRY, EMAIL, PHONE, BIRTHDAY) values ('Scotty','Scotland','scotabe@sc.sc','12345678','8 February');")
DBExecute("insert into info (NAME, COUNTRY, EMAIL, PHONE, BIRTHDAY) values ('Spock','Vulcan','spock@vu.vu','12345678','9 February');")
DBExecute("insert into info (NAME, COUNTRY, EMAIL, PHONE, BIRTHDAY) values ('Jim','Starbase','jum@sb.sb','12345678','10 February');")

//Do a database query on all friends
recordcount = DBQuery("select * from info;")

//read all the retieved records - reuse the fields$ array for the data
FOR i% = 0 TO recordcount-1       //for each record retrieved
DBRead(i,fields$[])           //read the record into the fields array
FOR j% = 0 TO LEN(fields$)-1  //for each field in the record
DEBUG fields$[j]+"   "    //display the data
NEXT
DEBUG "\n"
NEXT

END

//---------------------------------------------------------------------
//Reads a retrieved database record
//---------------------------------------------------------------------
FUNCTION DBRead: record%, array$[]
LOCAL s$,_data$[]
s$ = SQL.DBgetRecord$(record)
SPLITSTR(s$,_data$[],";")
FOR i% = 0 TO LEN(_data$)-1
array$[i] = _data$[i]
NEXT
ENDFUNCTION


//---------------------------------------------------------------------
//Query the database - returns number of records found
//---------------------------------------------------------------------
FUNCTION DBQuery: query$
SQL.DBdoSql(query$)
RETURN SQL.DBgetRecordcount()
ENDFUNCTION


//---------------------------------------------------------------------
//Execute a sql command
//---------------------------------------------------------------------
FUNCTION DBExecute: command$
SQL.DBdoSql(command$)
ENDFUNCTION


//---------------------------------------------------------------------
//Create databse table from field$ array
//---------------------------------------------------------------------
FUNCTION DBCreateTable: tableName$
LOCAL s$ = "create table " + tableName$ + "("
FOR i% = 0 TO LEN(fields$)-1
s$ = s$ + fields$[i]+" text"
IF i < LEN(fields$)-1 THEN s$ = s$ + ", "
NEXT
s$ = s$ + ");"
SQL.DBdoSql(s$)
ENDFUNCTION


//---------------------------------------------------------------------
//Initialize the database - open in with a database name
//---------------------------------------------------------------------
FUNCTION DBInit: databaseName$
SQL.DBSetName(databaseName$)
ENDFUNCTION


//---------------------------------------------------------------------
//Set the dabase debugging on or off
//---------------------------------------------------------------------
FUNCTION DBSetDebug: state
IF state
SQL.DBdebugOn()
ELSE
SQL.DBdebugOff()
ENDIF
ENDFUNCTION

#6
FAQ / Re: Generic Questions
2013-Feb-01
Here's my attempt at a solution to a color changer - Hope you find it useful.
Click on the color to change. Set the new color in the ChangeColors function.
Images for this demo are attached.


Code (glbasic) Select
// ------------------------------------------- //
// Project:     image_utils_6
// Description: Simple image color changer
// ------------------------------------------- //

GLOBAL px%[]   //buffer  - global to be seen by functions

LOCAL  mx,my,mbl,mbr
LOCAL currColor
LOCAL MBLDown = FALSE   //is mouse button-left down?

//load the image
LOADSPRITE "colorbox.png", 1

//load cursor
LOADSPRITE "cursor.png", 2


//main process loop
WHILE TRUE

//get mouse info
MOUSESTATE mx, my, mbl, mbr

//display input image sprite
DRAWSPRITE 1, 0,0

//get pixel color under mouse - if left mouse button is NOT down
IF NOT mbl THEN currColor = GETPIXEL(mx,my)

//draw a rectangle to show current color
DRAWRECT 450,20, 100, 100, currColor

//if left mouse button then change color
IF mbl AND NOT MBLDown
ChangeColors(currColor)
MBLDown = TRUE
ENDIF

//if left mouse button up, reset indicator
IF NOT mbl THEN MBLDown = FALSE

//draw mouse cursor - Always draw last to appear on top
DRAWSPRITE 2,mx,my

SHOWSCREEN
WEND

FUNCTION ChangeColors: color#
LOCAL width%, height%
LOCAL newColor = RGB(0,0,0) //color for replacement
LOCAL abgr%, r%, g%, b%, a%
LOCAL cabgr%, cr%, cg%, cb%, ca%

//break down color components
cabgr = color
cr = bAND(cabgr, 0xff)
cg = bAND(ASR(cabgr,8), 0xff)
cb = bAND(ASR(cabgr,16), 0xff)
ca = bAND(ASR(cabgr,24), 0xff)

//get sprite info
GETSPRITESIZE 1, width, height

//drop into sprite into buffer
SPRITE2MEM (px[],1)

//replace all occurences of color, with newcolor
//since the buffer is one long entity, we just loop through the data in sequene
FOR i% = 0 TO (width*height)-1

//break down sprite color components
abgr% = px[i]
r = bAND(abgr, 0xff)
g = bAND(ASR(abgr,8), 0xff)
b = bAND(ASR(abgr,16), 0xff)
a = bAND(ASR(abgr,24), 0xff)

//test and change
IF r = cr AND g = cg AND b = cb
px[i] = newColor
ENDIF

NEXT

//put buffer back into sprite
MEM2SPRITE(px[], 1, width, height)

ENDFUNCTION


[attachment deleted by admin]
#7
I'm really getting the hang of GLBasic now. It's time to give back for all the help I've received on the forum.

ISAM.gbal is included in the attached zip file, together with all sources.

ISAM is a GLBasic library that uses a UNIX concept of an indexed database.
ISAM stands for Indexed Sequential Access Method. A way of storing indexed data in a text file.

The library provides a TYPE named _ISAM, which can be used to manage simple databases on all platforms
The database is used in memory, and it can be saved to a textfile, and later loaded on demand

You can use as many databases at the same time as you wish.
You declare a database by using the _ISAM TYPE

friends AS _ISAM -is all that is needed to initialize the database
You can have as many rows and columns in the database as you wish.
You don't waste memory because row/column fields are only created when you "set" them.
All data is saved as strings, so you will need to convert the data if you wish to use them as numbers.

The ISAM library source
Code (glbasic) Select
// ------------------------------------------------------- //
// Project: ISAM
// Indexed Sequential Access Method Database file Manager
// ------------------------------------------------------ //


TYPE _ISAMINFO
index$
field$[]
info$[]
ENDTYPE

TYPE _ISAM
info[] AS _ISAMINFO

//! set: This function sets a variable to the database.
//! The index is used as a key to a table row
//! Each table row may have multiple fields, but must use the same index to add the field to the row
//! Each entry is only stored as a string. You will need to convert it in your code, if you wish to use numbers
//! If a field already exists, the data in that field will be updated.
//!
//! Parameters:
//! index$: The index for the row in the database
//! field$: The name of the column field in the index row of the database
//! info$ : The info you wish to store in the database field$ in the index$ row
//!
//! Returns: Nothing
//!
//! Example: set("JoeH", "Name", "Joseph"); set("JoeH","Surname","Higgins")
FUNCTION set: index$, field$, info$
LOCAL i,L,j,found
L=LEN(self.info[])
found = FALSE
FOR i = 0 TO LEN(self.info[])-1
IF index$ = self.info[i].index$
//first look for item to replace
FOR j = 0 TO LEN(self.info[i].field$[])-1
IF self.info[i].field$[j] = field$
self.info[i].info$[j] = info$
RETURN //change made - skip rest of function
ENDIF
NEXT
DIMPUSH self.info[i].field$[], field$
DIMPUSH self.info[i].info$[],info$
found=TRUE
BREAK
ENDIF
NEXT
IF NOT found
L=BOUNDS(self.info[], 0)
REDIM self.info[L+1]
self.info[L].index$ = index$
DIMPUSH self.info[L].field$[], field$
DIMPUSH self.info[L].info$[],info$
ENDIF
ENDFUNCTION

//! get: This function gets a variable from the database.
//! The index is used as a key to a table row
//! The index and the field must exist in the database, else the function returns a blank string
//!
//! Parameters:
//! index$: The index for the row in the database
//! field$: The name of the column field in the index row of the database
//!
//! Returns: On success, rerurns the info from the field. On failure, returns a blank string
//!
//! Example: name$ = get("JoeH", "Name")
FUNCTION get$: index$, field$
LOCAL i,j,L
LOCAL info$
FOR i = 0 TO LEN(self.info[])-1
IF index$ = self.info[i].index$
FOR j = 0 TO LEN(self.info[i].field$[])-1
IF self.info[i].field$[j] = field$
info$ = self.info[i].info$[j]
RETURN info$
ENDIF
NEXT
ENDIF
NEXT
RETURN ""
ENDFUNCTION

//! indexcount: This function returns the number of rows in the database.
//!
//! Parameters:
//! None
//!
//! Returns: The number of rows in the database
//!
//! Example: rows% = indexcount()
FUNCTION indexcount:
RETURN LEN(self.info[])
ENDFUNCTION

//! getindex$: This function gets the index string for the specified database row
//!
//! Parameters:
//! num%:  The number of the database row to access
//!
//! Returns: The index string for the specified database row
//!
//! Example: index$ = getindex$(2)
FUNCTION getindex$: num%
IF LEN(self.info[]) < 1 THEN RETURN
RETURN self.info[num].index$
ENDFUNCTION

//! fieldcount: This function gets the number of fields in an indexed database row
//!
//! Parameters:
//! index$: The index name of the database row to query
//!
//! Returns: The number of fields in the indexed row, or 0 if there are no fields
//!
//! Example: numFields = fieldcount("JoeH")
FUNCTION fieldcount: index$
LOCAL i
FOR i = 0 TO LEN(self.info[])-1
IF self.info[i].index$ = index$
RETURN LEN(self.info[i].field$[])
ENDIF
NEXT
RETURN 0
ENDFUNCTION

//! getfield$: This function gets the name of the specified field column number in the indexed row
//!
//! Parameters:
//! index$: The index name for the database row
//! num%:   The number of the field column in the row
//!
//! Returns: The name of the field column, or "" if the field does not exist
//!
//! Example: filed/name$ = getfield$("JoeH", 1)
FUNCTION getfield$: index$, num%
LOCAL i,j,L
FOR i = 0 TO LEN(self.info[])-1
IF self.info[i].index$ = index$
RETURN self.info[i].field$[num]
ENDIF
NEXT
RETURN ""
ENDFUNCTION

//! delindex: This function deletes an entire indexed row from the database
//! Note: This action is not reversable.
//!
//! Parameters:
//! index$: The index name of the database row ro delete
//!
//! Returns: 1 on success, -1 on failure
//!
//! Example: delindex("JoeH")
FUNCTION delindex: index$
LOCAL i,L
FOR i = 0 TO LEN(self.info[])-1
IF self.info[i].index$ = index$
DIMDEL self.info[],i
RETURN 1
ENDIF
NEXT
RETURN -1
ENDFUNCTION

//! save: This function saves the entire database as a textfile to disk
//!
//! Parameters:
//! filename$: The file name to which to save the database
//!
//! Returns: 1 on success, -1 on failure
//!
//! Example: save("myfriends.db")
FUNCTION save: filename$
LOCAL ok = OPENFILE(1, filename$,0)
LOCAL i,j,s$
IF NOT ok THEN RETURN -1
s$ = LEN(self.info[])
WRITESTR 1, s$+"\n"
FOR i = 0 TO LEN(self.info[])-1
WRITESTR 1, self.info[i].index$ + "\n"
s$ = LEN(self.info[i].field$[])
WRITESTR 1,s$ + "\n"
FOR j = 0 TO LEN(self.info[i].field$[])-1
WRITESTR 1, self.info[i].field$[j]+"\n"
WRITESTR 1, self.info[i].info$[j]+"\n"
NEXT
NEXT
CLOSEFILE 1
RETURN 1
ENDFUNCTION


//! load: This function loads a previously saved database back into memory
//!
//! Parameters:
//! filename$: The file name from which to read the database
//!
//! Returns: 1 on success, -1 on failure
//!
//! Example: load("myfriends.db")
FUNCTION load: filename$
REDIM self.info[0]
IF NOT DOESFILEEXIST(filename$) THEN RETURN -1
LOCAL ok = OPENFILE(1, filename$,1)
IF NOT ok THEN RETURN -1
LOCAL xi,xj,xIdxcount%,xfieldcnt%, s$
LOCAL xindex$,xfield$,xinfo$
IF NOT ok THEN RETURN
READLINE 1,s$
xIdxcount =  s$
FOR xi = 0 TO xIdxcount-1
READLINE 1, xindex$
READLINE 1, s$
xfieldcnt = s$
FOR xj = 0 TO xfieldcnt -1
READLINE 1,xfield$
READLINE 1,xinfo$
self.set(xindex$,xfield$,xinfo$)
NEXT
NEXT
CLOSEFILE 1
RETURN 1
ENDFUNCTION
ENDTYPE

//! ISAM is a GLBasic library that uses a UNIX concept of an indexed database.
//! ISAM stands for Indexed Sequential Access Method. A way of storing indexed data in a text file.
//!
//! The library provides a TYPE named _ISAM, which can be used to manage simple databases on all platforms
//! The database is used in memory, and it can be saved to a textfile, and later loaded on demand
//!
//! You can use as many databases at the same time as you wish.
//! You declare a database by using the _ISAM TYPE
//!
//! friends AS _ISAM    -is all that is needed to initialize the database
//! You can have as many rows and columns in the database as you wish.
//! You don't waste memory because row/column fields are only created when you "set" them.
//! All data is saved as strings, so you will need to convert the data if you wish to use them as numbers.
//!
//!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! An example of using the database
//!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//!
//! LOCAL friends AS _ISAM
//! LOCAL info$
//! LOCAL i
//! LOCAL field$
//! LOCAL index$
//!
//! friends.set("JoeH","Name","Joe")
//! friends.set("JoeH","Surname","Higgins")
//! friends.set("JoeH","Phone","123-4567")
//! friends.set("JoeH","Birthday","12-12-90")
//! friends.set("JoeH","Email","joeh@somewhere.earth")
//!
//! friends.set("AnneP","Name","Anne")
//! friends.set("AnneP","Surname","Pigtails")
//! friends.set("AnneP","Phone","765-4321")
//! friends.set("AnneP","Birthday","11-11-91")
//! friends.set("AnneP","Email","annepig@somewhere.moon")
//!
//! friends.set("AlbertE","Name","Albert")
//! friends.set("AlbertE","Surname","Einstein")
//! friends.set("AlbertE","Phone","755-1212")
//! friends.set("AlbertE","Birthday","01-01-1901")
//! friends.set("AlbertE","Email","albert.einstein@relativity.e=mc2")
//!
//! friends.set("SrIsac","Name","Isac")
//! friends.set("SrIsac","Surname","Newton")
//! friends.set("SrIsac","Phone","001-00706")
//! friends.set("SrIsac","Birthday","11-11-61")
//! friends.set("SrIsac","Email","isac.apple@under.tree")
//! friends.set("SrIsac","Birthday","03-03-63") //change
//!
//! DEBUG friends.indexcount()
//!
//! FOR i = 0 TO friends.indexcount()-1
//! DEBUG friends.getindex$(i)+"\n"
//! NEXT
//!
//! friends.delindex("AlbertE")
//!
//! index$ = friends.getindex$(2)
//!
//! DEBUG "\n"
//!
//! FOR i = 0 TO friends.fieldcount(index$)-1
//! DEBUG friends.getfield$(index$, i)+"\n"
//! NEXT
//!
//! DEBUG "\n"
//!
//! FOR i = 0 TO friends.fieldcount(index$)-1
//! field$ = friends.getfield$(index$, i)
//! DEBUG friends.get$(index$,field$)+"\n"
//! NEXT
//!
//! friends.save("testfile")
//!
//! friends.load("testfile")
FUNCTION __help__:
ENDFUNCTION


The ISAM test program
Code (glbasic) Select
// --------------------------------- //
// Project: ISAM - Testfile
// --------------------------------- //

LOCAL friends AS _ISAM
LOCAL info$
LOCAL i
LOCAL field$
LOCAL index$

friends.set("JoeH","Name","Joe")
friends.set("JoeH","Surname","Higgins")
friends.set("JoeH","Phone","123-4567")
friends.set("JoeH","Birthday","12-12-90")
friends.set("JoeH","Email","joeh@somewhere.earth")

friends.set("AnneP","Name","Anne")
friends.set("AnneP","Surname","Pigtails")
friends.set("AnneP","Phone","765-4321")
friends.set("AnneP","Birthday","11-11-91")
friends.set("AnneP","Email","annepig@somewhere.moon")

friends.set("AlbertE","Name","Albert")
friends.set("AlbertE","Surname","Einstein")
friends.set("AlbertE","Phone","755-1212")
friends.set("AlbertE","Birthday","01-01-1901")
friends.set("AlbertE","Email","albert.einstein@relativity.e=mc2")

friends.set("SrIsac","Name","Isac")
friends.set("SrIsac","Surname","Newton")
friends.set("SrIsac","Phone","001-00706")
friends.set("SrIsac","Birthday","11-11-61")
friends.set("SrIsac","Email","isac.apple@under.tree")
friends.set("SrIsac","Birthday","03-03-63") //change

DEBUG friends.indexcount()

FOR i = 0 TO friends.indexcount()-1
DEBUG friends.getindex$(i)+"\n"
NEXT

friends.delindex("AlbertE")

index$ = friends.getindex$(2)

DEBUG "\n"

FOR i = 0 TO friends.fieldcount(index$)-1
DEBUG friends.getfield$(index$, i)+"\n"
NEXT

DEBUG "\n"

FOR i = 0 TO friends.fieldcount(index$)-1
field$ = friends.getfield$(index$, i)
DEBUG friends.get$(index$,field$)+"\n"
NEXT

friends.save("testfile")

friends.load("testfile")



[attachment deleted by admin]
#8
FAQ / Re: Generic Questions
2013-Jan-27
The SPRITE2MEM reference in the help is pretty useful for that. You will need to sequentially traverse through the pixels to pick up their individual colors. a=alpha. r,g,b are self explanatory. x=sprite column, y=sprite row. width=width of sprite.

Quote
//SPRITE2MEM()
ok = SPRITE2MEM(pixels%[], num%)

LOCAL r%,g%,b%,a%
LOCAL abgr% = pixels%[x + y*width]
r = bAND(abgr, 0xff)
g = bAND(ASR(abgr,8), 0xff)
b = bAND(ASR(abgr,16), 0xff)
a = bAND(ASR(abgr,24), 0xff)
#9
The function works ok inside a TYPE. Unless I am misunderstanding your problem

Code (glbasic) Select
TYPE TESTType
t$[]
w$[]

FUNCTION Test1:
DIM self.t$[0]
DIM self.w$[0]
DIMPUSH self.t$[], "123"
DIMPUSH self.t$[], "456"
DIMPUSH self.t$[], "789"
DIMPUSH self.w$[], self.MyFunc$(self.t$[1])
DEBUG self.w$[0] + "\n"
ENDFUNCTION

FUNCTION MyFunc$: tt$
LOCAL x$ = "hello"
x$ = x$ + tt$
RETURN x$
ENDFUNCTION

ENDTYPE

LOCAL test AS TESTType

test.Test1()
#10
It works ok if the function is named MyFunc$ so that it can return a string. Set Debug mode, and check the output.

Here's my test
Code (glbasic) Select

GLOBAL w$[]
GLOBAL t$[]
LOCAL m$

DIMPUSH t$[], "123"
DIMPUSH t$[], "456"
DIMPUSH t$[], "789"

m$ = MyFunc$("abc")
DEBUG m$ + "\n"   //<-- outputs "helloabc"

DIMPUSH w$[], MyFunc$(t$[1])
DEBUG w$[0] + "\n"    //<-- outputs "hello456"

FUNCTION MyFunc$: tt$
LOCAL x$ = "hello"
x$ = x$ + tt$
RETURN x$
ENDFUNCTION


Edit: I always make my empty arrays global so I can use then inside functions. Not in this case, but it's a habit.
#11
I use Rhino Nurbs modeler to build most of  my models. I never thought I would one day be able to code nurbs. This is awesome. Well worth an investigation. OGL seems to hold many powerful features as well. I think I am going to have a few busy weeks ahead assimilating all this stuff into some useful code.
Again thanks - You guys rock.
#12
@mentalthink: I'll certainly take a look at you code. Thank you

@Ocean: All of this OGL stuff is new to me, so I feel like a kid with a new Christmas toy. Thank you.
#13
I read up on beziers on the web and discovered that the function uses the second vertex as a control point. That's where I was going all wrong.
I've changed my approach and only "spline" every second "waypoint". This creates usable points with thir spline control points. This is a lot of fun.
I will need to study this Entity thingy to see how GLBasic handles 3D, so that I can one day move the objects with a mouse. Till then, I'm stuck with keys.
Anyway. I got it working now. Probably my biggest GLBasic program so far.

Here's the project.

Edit: Add and Remove keypoints not coded yet.

[attachment deleted by admin]
#14
I took on the challenge to make a 3D splined path editor, to test out my new GLBasic skills, and I got a reasonable demo working.
However I have run into a brick wall with the QuadraticBezier3d, Not the function itself, that works brilliantly, but I'm rather stuck on how to make a continuous spline that runs through all 4 points that I use. The idea is to increase the key points on request, and generate splines as required. But alas my skills have dried up at this point.
I use the Bezier curves library from Hemlos to do the splines, but I am missing something along the way.
Any guidance will be most welcome

I've made certain arrays Global in the library in order to access them in my program.

Here's the program so far.
Code (glbasic) Select

//SETCURRENTDIR("Media")

//LOADFONT "..smalfont.png", 1
//SETFONT 1

TYPE POINT
x#
y#
z#
ENDTYPE

GLOBAL points[] AS POINT
GLOBAL splines[] AS POINT
GLOBAL waypoints[] AS POINT
GLOBAL numPoints = 4  //Key points for generating bezier curve points
GLOBAL extent# = 300  //Set pixel graph size: 100 means from -100 to +100. Change to desired path scale
GLOBAL CALC = FALSE
GLOBAL maxPoints = 30 //Bexier points: MUST be divisable by 2, else the calculations will fall over
LOCAL keyPoint = 0    //current key point
LOCAL i
LOCAL steps#
LOCAL angle = 270
LOCAL UpAngle = 0
LOCAL distanceP# = 2.5
LOCAL help = 1


SetupPoints()

WHILE TRUE
IF KEY(203) THEN angle = angle - 1 //left arrow
IF KEY(205) THEN angle = angle + 1 //right arrow
IF KEY(200) THEN UpAngle = UpAngle +1 //up arrow
IF KEY(208) THEN UpAngle = UpAngle -1 //down arrow
IF KEY(59) THEN help = -help; WHILE KEY(59); WEND //F1
IF KEY(15) THEN keyPoint = keyPoint+1;WHILE KEY(15); WEND //Tab
IF keyPoint > numPoints-1 THEN keyPoint = 0

IF KEY(17) //W
INC points[keyPoint].z 
CALC = FALSE
ENDIF

IF KEY(31) //S
DEC points[keyPoint].z 
CALC = FALSE
ENDIF

IF KEY(30) //A
INC points[keyPoint].x   //Reverse this if you prefer
CALC = FALSE
ENDIF

IF KEY(32) //D
DEC points[keyPoint].x  //Reverse this if you prefer
CALC = FALSE
ENDIF

IF KEY(19) //R
INC points[keyPoint].y 
CALC = FALSE
ENDIF

IF KEY(33) //F
DEC points[keyPoint].y 
CALC = FALSE
ENDIF



X_MAKE3D 1, 10000, 45
X_CAMERA COS(angle)*extent*distanceP, SIN(UpAngle)*extent*distanceP, SIN(angle)*extent*distanceP,  0, 0, 0

//grid
steps = extent*2/20
FOR i = -extent TO extent STEP steps
// XY grid
X_LINE -extent,i,0, extent,i,0, 0.1, RGB(0,0,60)
X_LINE i,-extent,0, i,extent,0, 0.1, RGB(0,0,60)
// XZ grid
X_LINE -extent,0,i, extent,0,i, 0.1, RGB(60,0,0)
X_LINE i,0,-extent, i,0,extent, 0.1, RGB(60,0,0)
//YX grid
X_LINE 0,-extent,i, 0,extent,i, 0.1, RGB(0,60,0)
X_LINE 0,i,-extent, 0,i,extent, 0.1, RGB(0,60,0)
NEXT

//z=0 indicator
X_LINE 0,0,0, 0,0,extent, 3, RGB(255,0,0)

//draw points
FOR i = 0 TO numPoints-1
IF i <> keyPoint
X_DOT points[i].x, points[i].y, points[i].z,10, RGB(0,255,0) //10=size of keypoint: change as required
ENDIF
NEXT

//draw current key point
X_DOT points[keyPoint].x, points[keyPoint].y, points[keyPoint].z,10, RGB(255,0,255) //10=size of keypoint: change as required


BuildSplineArray()


//draw all spline points
FOR i = 0 TO LEN(splines)-1
X_DOT splines[i].x, splines[i].y, splines[i].z, 1, RGB(180,180,180)
NEXT

//Screen instructions
X_MAKE2D
PRINT "F1: Toggle help", 5,5, RGB(200,200,200)
IF help = 1
PRINT "LEFT ARROW: Rotate Left", 5,25,RGB(200,200,200)
PRINT "RIGHT ARROW: Rotate Right", 5,45,RGB(200,200,200)
PRINT "UP ARROW: Rotate Up", 5,65,RGB(200,200,200)
PRINT "DOWN ARROW: Rotate Down", 5,85,RGB(200,200,200)
PRINT "1: Add Key Point", 5,105,RGB(200,200,200)
PRINT "2: Remove Key Point", 5,125,RGB(200,200,200)
PRINT "TAB: Next Key Point",5,145,RGB(200,200,200)
PRINT "W: Move Z+", 5,165,RGB(200,200,200)
PRINT "S: Move Z-",5,185,RGB(200,200,200)
PRINT "A: Move X-",5,205,RGB(200,200,200)
PRINT "D: Move X+",5,225,RGB(200,200,200)
PRINT "R: Move Y+",5,245,RGB(200,200,200)
PRINT "F: Move Y-",5,265,RGB(200,200,200)


ENDIF
PRINT "Number of Key Points: "+numPoints, 5,580, RGB(200,200,200)
SHOWSCREEN
WEND

FUNCTION SetupPoints:
LOCAL point AS POINT
point.x = -extent/2; point.y=0; point.z=0; DIMPUSH points[],point
point.x = 0; point.y=-extent/2; point.z=0; DIMPUSH points[],point
point.x = extent/2; point.y=0; point.z=0; DIMPUSH points[],point
point.x = 0; point.y=extent/2; point.z=0; DIMPUSH points[],point
ENDFUNCTION



FUNCTION BuildSplineArray:
LOCAL i,j,n,m,mhf,tx,ty,tz
LOCAL spline AS POINT

IF CALC THEN RETURN
CALC = TRUE

//Empty the spline array for new spline points
FOR i = 0 TO LEN(splines)-1
DIMDEL splines[],0
NEXT

//Empty the waypoint array for new waypoints
FOR i = 0 TO LEN(waypoints)-1
DIMDEL waypoints[],0
NEXT

//build new spline array
i= -1
WHILE TRUE
//DEBUG i + "\n"
i = i+1
IF i <= numPoints - 3
QuadraticBezier3d(points[i].x,   points[i].y,   points[i].z, _
                  points[i+1].x, points[i+1].y, points[i+1].z, _
                  points[i+2].x, points[i+2].y, points[i+2].z, _
                  maxPoints)
FOR j = 0 TO LEN(QuadraticBezierArray3d) -1
spline.x = QuadraticBezierArray3d[j][0]
spline.y = QuadraticBezierArray3d[j][1]
spline.z = QuadraticBezierArray3d[j][2]
DIMPUSH splines[],spline
NEXT
ENDIF

IF i = numPoints -2
QuadraticBezier3d(points[i].x,   points[i].y,   points[i].z, _
                  points[i+1].x, points[i+1].y, points[i+1].z, _
                  points[0].x, points[0].y, points[0].z, _
                  maxPoints)
FOR j = 0 TO LEN(QuadraticBezierArray3d) -1
spline.x = QuadraticBezierArray3d[j][0]
spline.y = QuadraticBezierArray3d[j][1]
spline.z = QuadraticBezierArray3d[j][2]
DIMPUSH splines[],spline
NEXT
ENDIF

IF i = numPoints -1
QuadraticBezier3d(points[i].x,   points[i].y,   points[i].z, _
                  points[0].x, points[0].y, points[0].z, _
                  points[1].x, points[1].y, points[1].z, _
                  maxPoints)
FOR j = 0 TO LEN(QuadraticBezierArray3d) -1
spline.x = QuadraticBezierArray3d[j][0]
spline.y = QuadraticBezierArray3d[j][1]
spline.z = QuadraticBezierArray3d[j][2]
DIMPUSH splines[],spline
NEXT
ENDIF

IF i = numPoints THEN BREAK
WEND

ENDFUNCTION


The full project is attached as well



[attachment deleted by admin]
#15
I did not use the "ing" version of the word for my search.. in help file and forum, so I missed your reference. Antialiasing levels I understand.
Thanks hardyx.