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

Topics - CW

#1
Has anyone seen the new 4k TVs?  :happy:
I am salivating at the idea of getting my hands on a 4k monitor and a graphics card to drive it. Because the pixels are four times smaller, the images are razor sharp. Cell phones and casino game machines are leading the way with this sort of image quality. For the PC, the technology is so new that there currently are no applications, operating systems (Windows), games, movies, or other software to support it, but I expect that to change in the next year or so. Once you see it, you've gotta have it.

I was curious if GLBasic plans to support such resolutions? (Is it even practical to dream so?) Wouldn't it be great to render drawings at 4K resolutions where each pixel is almost too small to see? True, every page would take 16 times longer to render on a pixel-by-pixel bases, but I can think of some great applications that I'd like to try, where speed isn't an issue. As for game creation, we might be able to load a background at 4K resolution and then move sprites in 4-bit increments without losing much to appearance or game performance. But then, I don't know anything about the heavy lifting which goes on in the background of GLB. What do you think? Might GLB be able to handle 4K? Is that something worth dreaming about?

-Science_1 

(PS, As it turns out Windows 8.1 can handle Ultra High-def; and also, apparently, can some games. See the Forbes article on a 4k game-PC system build.)
#2
Hi all!

I've been off enjoying my summer, but when I came across this article I thought of you.

Computer Scientists at UCLA have hit upon the holy grail of software protection. A protection method which allows full functionality of any program, yet any attempt to read the source code returns a number stream of pure garbage. The article gives only the sketchiest description of how it works; apparently the code is so mathematically folded in upon itself, with each part so mathematically interdependent upon the other parts (like a mathematical jigsaw puzzle) that the program will only execute if the encrypted whole is untouched. I wonder if a virtual machine recording how the program accesses virtual components could expose the functionality.. -the article doesn't say. If this method of protection can allow execution in real time without significant slowing, I'll bet we will see unbreakable software become the norm in the next few years. (The patent-holder is set to become VERY rich.) Suck it, China!  =D

Anyway, here is a link to the article for you to enjoy.
-CW

http://www.sciencedaily.com/releases/2013/07/130729161946.htm
#3
Hi all,

Today I was working on a key-mapping utility as part of my larger keyboard scanning function, based on the swift K=Key() command, and I came upon a puzzling absence in the font sets created by the GLbasic utility. The '&' symbol is missing. This isn't a big deal and is easily correct, but I am just curious as to if there is a reason the symbol isn't there.

Here is a bit of code to show the problem. Create a font, name it "smalfont.png", and save it to the Media folder. Then run the following:

Code (glbasic) Select

SETSCREEN 1366,768,FALSE
GLOBAL sw%,sh%,sm%
GETSCREENSIZE sw,sh
sm = sw/2
SETCURRENTDIR(GETCURRENTDIR$()+"Media")
GLOBAL fontkey = GENFONT(),fw%,fh%
LOADFONT "smalfont.png",fontkey
SETFONT fontkey
GETFONTSIZE fw,fh


PRINT "Ascii code 38 is the 'AND' sign,",50,fh,TRUE

LOCAL a$ = "&"
PRINT "Let a$ = "+CHR$(34)+"&"+CHR$(34)+".  Here is a$-> |"+a$+"|",50,fh*2,TRUE
PRINT "It is also CHR$(38). Here is CHR$(38)-> |"+CHR$(38)+"|",50,fh*3,TRUE

PRINT "The symbol is missing from GLbasic font creation utility.",50,fh*5,TRUE
PRINT "Is there a reason, or is it just a minor oversight?",50,fh*6,TRUE

PRINT "                     Press Key to Exit.",50,fh*8,TRUE

SHOWSCREEN;KEYWAIT


Thanks!
-CW

PS. Attached is a character set with my hand-drawn '&' symbol included, for anyone who might find it handy.
#4
Hi all,

I have been exploring KittyHello's DDgui toolbox, and I am very impressed with how fast, smooth, and handy DDgui is.
I had some trouble with it, though. I could not get it to run when loading it as an existing project from the GLbasic Samples folder. When attempted, I received the following error: (See attached image.) Debug mode gave no additional information.

It took me about an hour to get DDgui to work, and only after transplanting the 'DDgui_Test' main program, the 'Sources' code, and the associated apps folder to a fresh "sandbox" project, which I had made so as to work from a clean slate. I also had to reset the current directory and create a new custom font, and I'm not entirely sure I've captured full functionality.

The programing in DDgui is well over my head, and I wasn't able to do more than beat at it with a stick in the hopes that it would start to run for me. Fortunately, this approach seemed to work. I would love to see DDgui in its native state, as intended, so that I can assess its full capabilities (just in case I broke something when poking it with my stick.)

Has anyone else had this trouble, or does anyone know what the message, 'syntax error' in line one is referring to?

Thanks!
-CW

PS: If you haven't checked out DDgui yet, you definitely owe it to yourself to do so.
#5
-In a previous thread Lee and I began discussing plans for a spread-sheet style program which can manage up to eight rosters of units (eight players, or teams if you will) for use in live games such as D&D or Warhammer. Any game in which the players must keep track of a large number of units, their attributes and their health.

Lee wrote:
=======

Btw one little tip I can give you is read up on the basics of databases, things like different tables etc as believe me it will help with regards to data management as I'm sure your aware RPG's can be very heavy on data storage with various weapons/armor etc. Not only that but a well organised data structure makes retrieving what you need easier & more efficient on storage as well as access. A flat database like a spreadsheet becomes a nightmare to maintain when you start getting more data.

I used to use MySQL to handle my data but am looking into the sqlite wrapper that is posted elsewhere on this forum. Setting up a database with multiple tables requires a bit more setting up & planning but it rewards you afterwards with easy access & maintenance.

Obviously I don't know your experience with regards to databases but if you need an example of what I mean please let me know  =D

Lee
#6
The following is more of a feature request to improve Inkey$(), than a code-killing bug. There is a way to program around the issue, but it seems like such an ugly kludge. Could Inkey$() function as smoothly as Key()?
-CW
====================

Code (glbasic) Select

// Inkey$(): Feature or Bug?
//--------------------------
// First run using Test 1 code section
// Then turn it to commented lines,
// activate Test 2 code section and run again.
// Feature or Bug?
//---------------------------

SETCURRENTDIR(GETCURRENTDIR$()+"Media")
GLOBAL fontkey% = GENFONT()
LOADFONT "smalfont.png",fontkey


////////////////////////////////////////////////
//       Setup Static Background Screen                     
PRINT "GetKey$() Test",20,50
PRINT "Press [Backspace] key to quit.",20,75
USEASBMP;SHOWSCREEN
/////////////////////////////////////////////////
/////////////////////////////////////////////////

LOCAL K$ = ""
REPEAT

///////////////////////////
// Test 1: Refresh the screen only when a character is pressed, otherwise, continue to show the current screen, which displays the last key pressed.
//
// This test will fail for INKEY$() is never reset and so never checks the keyboard again.
// ------------------------
//

K$ = INKEY$()
IF K$ <> ""
PRINT "Key Press = "+K$,150,120
SHOWSCREEN
ENDIF


//
///////////////////////////////
// Test 2: Refresh the screen every loop. This seems to impose a huge overhead on using INKEY$() when the screen must be redrawn each and every
// time we check for a keypress. Shouldn't there be a way to reset INKEY$() directly, without calling SHOWSCREEN? Maybe something like K$=INKEY$(-1) ?
//
// This test will succeed, as INKEY$() is reset when SHOWSCREEN is called, and so is set to check the keyboard again the next time it comes around.
// ----------------------------
//

// K$ = INKEY$();SHOWSCREEN
// IF K$ <> ""
// PRINT "Key Press = "+K$,150,120
// ENDIF


//
////////////////////////////////

UNTIL KEY(14) // Exit when Del key is pressed.
#7
In my latest project, I don't want to pause program flow to wait on an INPUT or a KEYWAIT command. I need to handle input in real time and I want to make use of K%=KEY(x) to do it; scanning through all permissible input values. My question is this. How can I tell an uppercase letter (or character) from a lowercase letter? GL-Basic's KeyCode utility returns two values for a shift-letter, but how can I make use of this fact with KEY(), which only returns a single value?

I could use K$=INKEY$, convert K$ to ASCII, and then compare that value to permissible inputs, but the KEY() is supposed to be swifter. (I'm trying to avoid the overhead that comes with strings.) So before I go the INKEY$ route I figured I would ask you guys how you all handle this challenge. Is there an elegant way to detect capital letters using the KEY() command?

Thanks all.
-CW
#8
I'm thinking of taking another run at a project I've attempted a few times in the past, but have never had success in programing. I would like to create a game-board engine which can handle the management of hexagons.

The engine would define a new type, called TYPE: HEX. Commands this engine would support would be to draw a hexagon game board of any size the user wants (provided it fits on the screen), dimension the memory-array to efficiently contain the game board hexes, place or remove an object (well an object number) into or from a given hex, check surrounding hexes of any desired radius for objects (obstacles, targets, firing range), return the distance from a given hex to any other hex, check line of sight to another hex, plot movement paths to another hex while avoiding obstacles, determine front/back/side facing of an object to another hex, and transparently handle all of the mapping of the hexagon game board and objects to the square grid of the memory array.

I'm a war-gamer from way back, and I have always loved paper-map games played on hexagons, so it is natural that I should love computer games played on hexagons too. My question (before taking another stab at this project) is, has anyone already created such an engine in GL-Basic? I don't want to reinvent the wheel when I can be playing with the game mechanics instead.  :)

I have failed at this project a few times before, but I get closer each time I try. If anyone has any advice on programing such an engine, please share!

Attached is an image which shows what I have learned from previous studies of this challenge. The illustrations shows how a hexagon game-board can be created out of squares, and how the square-hexagons can be efficiently stored in a computer array. But notice the odd mapping of the hexes onto the memory array, and notice how that pattern flips when the center object (center hex) moves one hex north or south. (North, in this case.) This flipping of the pattern happens each time an object moves a row north or south on the game field, and it is that patten which makes it very difficult to plot movement based on the computer array. You can't even use simple trig functions to determine cells present at a given radius in either the computer array or the hexagon game board (because the hex shape on the game board very quickly fails to conform to that of a circle, so you gather increasingly greater numbers of false positives.)

It's an interesting problem that I'd like to share with everyone here in the hope that, even if I fail on this attempt too, maybe I can infect you with the bug to crack this problem and give our GLBasic community the ability to create games on hexagonal game boards.

-CW
#9
It is with great pride that I share my new Custom Color Wheel function. What started out as a one-day project grabbed hold of me, and it took me 12 days to complete.

This function may come in handy for anyone who is working on a paint program, or any customization routine, or any program in which the programer would like to give the user more than a dozen colors to choose from. The demonstration program calls on the ColorWheel function so that you can choose a color for the screen. (Yeah, I know. It's a boring example. But I think you will recognize the potential.)

Rendering all of those colors was a real challenge as the SETPIXEL command is deathly slow. To manage this limitation, the Function attempts to load a PNG image of the colorwheels, and only if that file can not be found does it render a new set of color wheels and saves them to the PNG image file for next time. The down side to loading the PNG image is that the calculations for pixel color selection are highly dependent on the loaded image being in EXACTLY the right place, so if the screensize is changed, the image file will no longer map to the calculated values. Therefore, if you change the screen size, you will need to either delete the colorwheel PNG image from the CWFILES folder, or you will need to set Delete_ColorWhl_Flg = TRUE for a single run of the program. I apologize for the hassle, but it is worth it for the speed gained in loading the image rather than generating it from scratch.

The PNG image file is not included, so the first time you run this function, it will render the color wheels to match your system as you watch; and then it will save the PNG image to the CWFILES folder. I tried rendering the wheels off-screen, which was faster, but also much more boring. Rendering on screen gives you something to look at.

You may be interested in knowing that the GETPIXEL() command is not used. First of all, because it is far too slow for this function, and secondly because the colors it attempts to read from an image can be off. The beauty of this function is its speed and precision. Each pixel color is exact, for the algorithm which calculates the pixel color is the same algorithm which rendered the image in the first place.   

This brings me nicely to the next item. Parameters.
There are three parameters available to the programer at the start of the ColorWheel function.

The first, as I've already mentioned, tells the computer to delete the png image and render it anew.

The second allows you to turn on and display, or turn off and not display, an "OK" button on the main color wheel screen.
The OK button allows the user to exit with his or her chosen color immediately from the colorwheel screen. If this parameter is set to FALSE, the user must exit the function by way of the Slider Screen (which is obtained by clicking the Right mouse button.) Changing the setting on this parameter will require rendering the ColorWheel image anew, so that the button is displayed on the static screen image.

The third parameter sets a delay timer which is used on the Slider Screen, used for the RGB incremental buttons on either side of each R, G, and B sliders. Increase or decrease this timer (which watches the system clock) to your liking. The delay can be turned off altogether for a swift and smooth slide. But this can make setting exact numbers difficult.

I have allowed within the function, a place to accommodate additional features. This area is duly marked by comments. One feature which I may implement, if I find its absence annoying, is a way to enter numerical RGB values directly from the keyboard. But that is a feature for a future version which I did not feel the need for presently, given the size of the function in its current form and the time I have spent on it. (This started out as a feature for my Animation Spreadsheet project, and I am anxious to get back to this main project.)

In the course of writing this function I learned some really interesting things regarding to the Color Wheels and their color locations on the three-dimensional color-cube containing all possible colors which our computers can display. My next project will be to type up a post on these interesting, wonderfully mind-twisty things. When I do, I will post it to this thread.

Cheers!
-CW     

#10
I am placing the finishing touches on a nifty function which may be useful with many different applications. I'd like to use both a custom directory and a custom font with the function, and than restore the original directory and font when the function exits. The directory is no problem, as we have the GETCURRENTDIR$() & SETCURRENTDIR() commands, but the font has me stumped.

If I use Fontkey% = GENFONT() in my function, is there a way to discover before I call it, from within the function, which font number is currently set so that I can restore it when I exit? Also, is there a way to UNLOAD(Fontkey) and free up the memory occupied by the custom font, which was set aside by the LOADFONT command using Fontkey = GENFONT?

Yes, I could require the programer to pass Fontkey to the function, but that seems so ugly and inelegant. It seems there should be a counterpart to GETCURRENTDIR$() for fonts.

Thanks!
-CW
#11
Hey all, I need someone to help jog my memory.

I seem to remember reading somewhere that it is possible to declare optional arguments which can be passed to a function, but which can be omitted; in which case the function uses the default value. I can't find that text again, now that I need the ability. (Was it in GLbasic?)

It would look something like: (Just a quick and dirty example..)

FUNCTION Example: x%,y%, [color% = 0]    //where color% can either be passed, or not, by the calling program.
  SETPIXEL x,y,color
ENDFUNCTION

If memory serves, optional arguments are allowed provided they are placed at the end of the declaration.
I COULD create two or more variations on the same function, or create nesting wrappers around the functions, but why create two when one will do?

Can someone give me a hand?   :)

-CW
#12
Off Topic / Lost Code?
2013-Mar-18
I'm a little ticked today. I arrived at the library this morning to do some coding, only to discover that I did not bring the latest version of my Color Wheel program with me.  :glare: Annoying, right? Yeah, but not too bad. So I walked back home, transferred the latest file to my thumb-drive, and then drove to the library again. There I discovered that the night before I had, somehow, overwritten my latest version with an earlier version! Gah! An entire day's programing lost :rant: It was late. That's what I get for not knowing when to stop and call it a night.  :bed:

I am now back home, where I have recovered the version previous to that; but now I'm not much in the mood for programing. Maybe I should crawl back into bed with the cat. =^..^=
It's just one of those days.

I'm glad I make regular backups. The loss wasn't too bad, just one day. But it is frustrating. My question to you is, what is the worst code-loss you have ever experienced, and how did it happen? Any stories you'd like to share?

I once lost a week's worth of coding, years ago (when I never bothered with backups) after one bad revision attempt in the spaghetti-code I used to write wound up trashing the program and got me hopelessly lost in the weeds, in a way that was beyond fixing. The more I tried to undo the damage, the more I screwed it up.  :giveup:
Ah well. Lesson learned. What about you?
-CW
#13
Hi all,

I've scoured the search fields but couldn't find any threads directly related to my question.

I have written some really handy personal functions in GLBASIC, which may come in handy for future projects. Some of the functions are quite beefy in size, if you know what I mean, so it would be nice to move them off program and call them as needed using something similar to the "include" command, used for C++ code. Does GLBASC support some form of this, or will I just have to cut and paste my BASIC functions into future projects? An ability to call external GLBASIC functions, and compose my own personal libraries would streamline future programs; so I thought it was worth asking about.

Thanks!
-CW
#14
This is just a little thing I threw together in a day. I've been thinking of doing a tank-battle type of game, but I needed a way to set shot angle and power, and than let the program plot the trajectory under gravity from there. Vector math to the rescue! That lead to setting random angles and power levels, and plotting LOTS of projectiles in this little volcano program. How many particles can your rig comfortably maintain? To maximize rendering speed, I do no keyboard or mouse checks. Press Esc to exit, or just wait for the cycle count to complete. Happy Coding!
-CW
Code (glbasic) Select

/////////////////////////////////////////////////////////////////////////
//                             VOLCANO
// Written by Craig Waterman
// 01/25/13
// ----------------------------------------------------------------------
// This project uses vector math to animate a small volcano.

/////////////////////////////////////////////////////////////////////////

////////////////////////////  Initialize  ///////////////////////////////
//
// Change PARTICLE_COUNT to set number of particles to use.
// (Try 0 to 100000, or more. How many can your machine handle?)

CONSTANT PARTICLE_COUNT = 3000

GLOBAL sx,sy
GETSCREENSIZE sx, sy // Volcano is positioned in the center of the screen. (Screen can be resized.)

LOCAL Altitude%,Horizontal_Location%
LOCAL Path$=GETCURRENTDIR$()
LOADFONT Path$+"MyFont1.png",1
SETFONT 1

TYPE Particle
Particle_Number#
X_Velocity = 0.0
X_Birth_Tick# = 0 // Hold the clock tick when a particle is born. Trajectory is based on time from birth.
Y_Velocity = 0.0
Color% = 0.0
ENDTYPE

GLOBAL Particles[] AS Particle,Surge
DIM Particles[PARTICLE_COUNT+1] // Up to PARTICLE_COUNT particles will simultaneously erupt from the volcano.
// Note that the count begins with zero, but the dim needs one extra to properly format.
            // Format: Particles[Particle Number][X_Velocity][Y_Velocity][Color of particle in RGB(value,value,value)]

GOSUB Initialize_Particles
GOSUB DrawLandscape
/////////////////////////////// BODY ////////////////////////////////////////

FOR Tick = 0 TO 1000 //Tick is the number of clock cycles in the full animation.

FOR P_Inumerate = 0 TO PARTICLE_COUNT
Altitude = INTEGER(Particles[P_Inumerate].Y_Velocity*(Tick-Particles[P_Inumerate].X_Birth_Tick));IF Altitude <-13 THEN Altitude = -13
Particles[P_Inumerate].Y_Velocity=Particles[P_Inumerate].Y_Velocity - .32

IF Altitude >-13 // Top of volcano is 13 pixels high, so ground is at -13, and any particle at -13 needs to be reset.
    Horizontal_Location = (Particles[P_Inumerate].X_Velocity*(Tick-Particles[P_Inumerate].X_Birth_Tick) + (sx/2) )
    SETPIXEL Horizontal_Location,400-Altitude,Particles[P_Inumerate].Color
ELSE
Initialize_Particle(P_Inumerate,Tick)
ENDIF
NEXT // P_Inumerate
Surge = Surge + 1

SHOWSCREEN

NEXT // Tick

PRINT "Finished!",sx/2-60,sy/2+75
PRINT "Press Key",sx/2-60,sy/2+100
SHOWSCREEN
KEYWAIT
END
///////////////////////////////////////////////////////////////////
////////////////////////  Functions ///////////////////////////////
// ------------------------------------------------------------- //
// ---  VECTORCOMPONENT  ---
// ------------------------------------------------------------- //
FUNCTION Initialize_Particle: Particle_Num,BirthTick
LOCAL Angle#,Power%
Angle = RND(60)+60
Power = RND(1000)+525+INTEGER(COS(Surge*12)*75) //To add visual interest, I allow the projectile power to surge.
Particles[Particle_Num].X_Velocity = COS(Angle)*Power/100
Particles[Particle_Num].Y_Velocity = SIN(Angle)*Power/75
Particles[Particle_Num].Color = RGB(255,RND(100),255)// Violet color with a random greenish component.
Particles[Particle_Num].X_Birth_Tick = BirthTick
RETURN
ENDFUNCTION // VECTORCOMPONENTX
///////////////////////////////////////////////////////////////////
//////////////////////////  Subs  /////////////////////////////////
// ------------------------------------------------------------- //
// ---  DRAWLANDSCAPE  ---  I like a Minimalist Style.
// ------------------------------------------------------------- //
SUB DrawLandscape:

CLEARSCREEN
DRAWLINE 10,414,(sx-10),414,RGB(0,255,0) // Draw Ground

LOCAL VolcanoColor% = RGB(255,0,0)
DRAWLINE (sx/2-13),413,(sx/2-5),396,VolcanoColor;DRAWLINE (sx/2+13),413,(sx/2+5),396,VolcanoColor // Draw Volcano
DRAWLINE (sx/2-5),396,(sx/2+5),396,VolcanoColor// Draw Volcano
USEASBMP;SHOWSCREEN;SLEEP 500 //Delay .5 seconds to allow user to admire the landscape before the eruption.
ENDSUB // DRAWLANDSCAPE
// ------------------------------------------------------------- //
// ---  INITIALIZE_PARTICLES  ---
// ------------------------------------------------------------- //
SUB Initialize_Particles:
FOR Counter = 0 TO PARTICLE_COUNT
Initialize_Particle(Counter,0)
NEXT
ENDSUB // INITIALIZE_PARTICLES
///////////////////////////////////////////////////////////////////
#15
Hi all,

As the GLBasic math functions do not support imaginary or complex numbers, I created TYPE CMPLX and a basic set of function commands for their use.

You may want to create a small font for this program called "myfont.png", which is large enough to read. Otherwise the default mouse-font is hard on the eyes.

There is definitely room for spit and polish, and if anyone wants to offer or make improvements, you won't offend me.
The function, COMPLEX2STR$, for example, formats the complex number to a BYREF-passed string, because functions can only return a single value. Using it for printed output is a bit of a dance, but it was the only way I could figure to get the job done. Additionally, the string which the function creates has an abundance of parentheses from an abundance of caution on my part towards respecting the mathematical order of operations. There is room for simplicity, but you can enter the displayed equations exactly as shown into a TI-84 calculator and verify that the functions are calculating properly.

As a demonstration and for a bit of fun, I finished this program by using complex numbers to calculate a Mandelbrot Set.
The program is structured so that you can simply omit the function-demonstration and the Mandelbrot sub and use the Complex Type and Functions for your own programs.

Anyway, I hope you have as much fun messing with this program as I had writing it.
Cheers!  =D
-CW
Code (glbasic) Select

// --------------------------------- //
// Project: Complex_Numbers V_1.0
// Start: Sunday, March 03, 2013
// IDE Version: 10.283

//Please create a small font with text large enough for you to read and save it as "myfont.png".

      //////////////////////////////////////////////////////////
      //            Complex Number Command Set                //
      //------------------------------------------------------//
      //         Written by Craig Waterman. 3/03/13           //
///////////////////////////////////////////////////////////////////////
//                                                                   //
//                  Note to Reader                                   //
//                  --------------                                   //
// The body of this program contains a demonstration using each      //
// Complex Number function for variables defined as TYPE COMPLEX.    //
// Following the body are the functions themselves.                  //
// Following the functions is a modual which demostrates             //
// how to generate a Manderbal Set on the complex plane.             //
// The only way to create a Manderbel set is using complex numbers.  //
// Both the BODY secion and the Manderbel modual can be              //
// deleted cleanly, leaving just the Complex functions.              //
// Enjoy! -CW                                                        //
///////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////
///////                 BODY                 /////////
//////////////////////////////////////////////////////
GLOBAL SCREENWIDTH = 1000,SCREENHEIGHT = 510
SETSCREEN SCREENWIDTH,SCREENHEIGHT,0
LOADFONT "myfont.png",0
SETFONT 0

TYPE CMPLX
real# = 0.0
imaginary# = 0.0
ENDTYPE

LOCAL CMPLX_Answer AS CMPLX

LOCAL Var1 AS CMPLX
LOCAL Var2 AS CMPLX
LOCAL Var3 AS CMPLX
LOCAL HoldAnswer AS CMPLX
LOCAL MyString$

Var1.real = 4.0; Var1.imaginary = 2.0
Var2.real = 4.0; Var2.imaginary = -3.0

ADDCOMPLEX(Var1,Var2,HoldAnswer)
MyString$=""
COMPLEX2STR$(Var1,MyString$,TRUE);MyString$=MyString$+" + "
COMPLEX2STR$(Var2,MyString$,TRUE);MyString$=MyString$+" = "
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,10

Var3 = HoldAnswer
SUBTRACTCOMPLEX(Var3,Var1,HoldAnswer)
MyString$=""
COMPLEX2STR$(Var3,MyString$,TRUE);MyString$=MyString$+" - "
COMPLEX2STR$(Var1,MyString$,TRUE);MyString$=MyString$+" = "
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,30

MULTIPLYCOMPLEX(Var1,Var2,HoldAnswer) // Var1 * Var2 = HoldAnswer. (HoldAnswer holds the return answer.)
Var3 = HoldAnswer // Hang on to the mustiplication answer so we can use it for division later.
MyString$=""
COMPLEX2STR$(Var1,MyString$,TRUE);MyString$ = MyString$+" X "
COMPLEX2STR$(Var2,MyString$,TRUE);MyString$ = MyString$+" = "
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,50

DIVIDECOMPLEX(Var3,Var2,HoldAnswer)
MyString$=""
COMPLEX2STR$(Var3,MyString$,TRUE);MyString$=MyString$+" / "
COMPLEX2STR$(Var2,MyString$,TRUE);MyString$=MyString$+" = "
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,70
MyString$="";COMPLEX2STR$(Var1,MyString$,FALSE)

SQUARECOMPLEX(Var2,HoldAnswer)
MyString$="";
COMPLEX2STR$(Var2,MyString$,TRUE);MyString$ = MyString$+"^2 ="
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,90

RECIPCOMPLEX(Var1,HoldAnswer)
MyString$=""
COMPLEX2STR$(Var1,MyString$,TRUE);MyString$=MyString$+"^-1 = "
COMPLEX2STR$(HoldAnswer,MyString$,FALSE)
PRINT MyString$,30,110

PRINT "Press KEY to continue.",150,150

SHOWSCREEN;KEYWAIT

PRINT "Let's use complex numbers to calculate a Mandelbrot Set.",20,10
PRINT "Press KEY to begin.",250,50
SHOWSCREEN;KEYWAIT

GOSUB CREATE_MANDELBROT
SHOWSCREEN;KEYWAIT
END
///////////////////////////////////////////////////////////////////
//////                  END BODY                               //////
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//              Complex Number Functions.                        //
// ------------------------------------------------------------- //
//               ---  MULTIPLYCMPX  ---                          //
// ------------------------------------------------------------- //
FUNCTION MULTIPLYCOMPLEX:  Num1 AS CMPLX, Num2 AS CMPLX,Answer AS CMPLX
LOCAL Temp AS CMPLX // Temp is used so we won't have to change the value
// of the variable 'Answer' points to until the very end.
                    // This allows the user to call these functions with
                    // one variable and request that the answer be returned
                    // in the vary same variable. Without the Temp variable
                    // we would run into trouble overwriting values we still need.
Temp.real = (Num1.real * Num2.real) - (Num1.imaginary * Num2.imaginary)
Temp.imaginary = (Num1.real * Num2.imaginary) + (Num2.real * Num1.imaginary)
Answer = Temp
ENDFUNCTION // MULTIPLYCMPX
// ------------------------------------------------------------- //
// ---  ADDCOMPLEX  ---
// ------------------------------------------------------------- //
FUNCTION ADDCOMPLEX: n1 AS CMPLX, n2 AS CMPLX, Answer AS CMPLX
LOCAL Temp AS CMPLX
Temp.real = n1.real + n2.real
Temp.imaginary = n1.imaginary + n2.imaginary
Answer = Temp
ENDFUNCTION // ADDCOMPLEX
// ------------------------------------------------------------- //
// ---  SQRCOMPLX  ---
// ------------------------------------------------------------- //
FUNCTION SQUARECOMPLEX: CMPLX_Num AS CMPLX,Answer AS CMPLX
LOCAL Temp AS CMPLX
MULTIPLYCOMPLEX(CMPLX_Num,CMPLX_Num,Temp)
Answer = Temp
ENDFUNCTION // SQRCOMPLX
// ------------------------------------------------------------- //
// ---  DIVIDECOMLEX  ---
// ------------------------------------------------------------- //
FUNCTION DIVIDECOMPLEX: CMPLX_v1 AS CMPLX, CMPLX_v2 AS CMPLX, Answer AS CMPLX
LOCAL Inverse AS CMPLX,Temp AS CMPLX
RECIPCOMPLEX(CMPLX_v2,Inverse)
MULTIPLYCOMPLEX(CMPLX_v1,Inverse,Temp)
Answer = Temp
ENDFUNCTION // DIVIDECOMLEX
// ------------------------------------------------------------- //
// ---  SUBTRACTCOMPLEX  ---
// ------------------------------------------------------------- //
FUNCTION SUBTRACTCOMPLEX: n1 AS CMPLX, n2 AS CMPLX, Answer AS CMPLX
LOCAL Num AS CMPLX,Temp AS CMPLX
Num = n2
Num.real = -1*Num.real
Num.imaginary = -1*Num.imaginary
ADDCOMPLEX(n1,Num,Temp)
Answer=Temp
ENDFUNCTION // SUBTRACTCOMPLEX
// ------------------------------------------------------------- //
// ---  RECIPCOMPLEX  ---  Finds num^-1
// ------------------------------------------------------------- //
FUNCTION RECIPCOMPLEX: n1 AS CMPLX,Answer AS CMPLX
LOCAL Temp AS CMPLX
LOCAL LCD# = 0.0
LCD = POW(n1.real,2)+ POW(n1.imaginary,2)
Temp.real = (n1.real/LCD)
Temp.imaginary = (n1.imaginary / LCD *-1)
Answer=Temp
ENDFUNCTION // RECIPCOMPLEX
// ------------------------------------------------------------- //
// ---  COMPLEX2STR$  --- Note: Add_Parentheses = TRUE means place parentheses around the entire complex number.
// ------------------------------------------------------------- //
FUNCTION COMPLEX2STR$: CplxNum AS CMPLX, BYREF String$,Add_Parentheses%
LOCAL WorkStr$ = "",Hold$=""
IF Add_Parentheses = TRUE THEN String$=String$+"("
String$=String$+"("
WorkStr$=CplxNum.real
FOR counter = 0 TO LEN(WorkStr$);Hold$=MID$(WorkStr$,counter,1);IF Hold$<>" " THEN String$=String$+Hold$;NEXT //The system formats numbers with blank spaces for polarity sign. Strip the spaces out.
IF INSTR(WorkStr$,".",0) = -1;String$=String$+".0)+(" ;ELSE;String$=String$+")+(";ENDIF // We want whole numbers, such as "4", to be displayed as with decimals, such as "4.0"
WorkStr$=CplxNum.imaginary;Hold$=""
FOR counter = 0 TO LEN(WorkStr$);Hold$=MID$(WorkStr$,counter,1);IF Hold$<>" " THEN String$=String$+Hold$;NEXT //The system formats numbers with blank spaces for polarity sign. Strip the spaces out.
IF INSTR(WorkStr$,".",0) = -1; String$=String$+".0i)";ELSE;String$=String$+"i)";ENDIF // Display whole numbers, such as "4" as "4.0"
IF Add_Parentheses = TRUE THEN String$=String$+")"
ENDFUNCTION // COMPLEX2STR$
//////////////////////////////////////////////////////////////////
////                      END FUNCTIONS                       ////
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// ------------------------------------------------------------ //
//                 ---  CREATE_MANDELBROT  ---                  //
//         Demenstration, Use Of Complex Number Functions.      //
// ------------------------------------------------------------ //
//            Written by Craig Waterman, Jan, 2013              //
//--------------------------------------------------------------//
// Safe to delete this entire sub and all functions below it.   //
//////////////////////////////////////////////////////////////////

SUB CREATE_MANDELBROT:

// Mendalbrot Set Formula is Z=Z^2+C
LOCAL Z AS CMPLX
LOCAL C AS CMPLX
LOCAL Zero AS CMPLX // Zero has both components, real and imaginary, = 0. Used to clear CMPLX variable. (Ex: Z = Zero)

LOCAL MaxIterations#,Magnitude
LOCAL Cheat_For_Speed_Flag%
LOCAL PictureHeight_in_Pixels%,X_Pixels%,Y_Pixels%
LOCAL Fieldlength#,FieldShift#
LOCAL Mand_Start_X#,Mand_Start_Y#,Mand_End_X#,Mand_End_Y#,Mand_Rez_X#,Mand_Rez_Y#
LOCAL ColorPixelFlag%

////////////////////////////////////////
// User adjustable variables
//
PictureHeight_in_Pixels = 500  // Change these values to render a larger or smaller image. Keep it within your computers max screen size.
MaxIterations# = 1000 // You have to stop iterating sometime, and a maximum of 1000 iterations is sufficient for our resolution.
                      // Higher magnifications of the Mandelbrot set can require more iterations TO bring out the detail.
Magnitude = 3000      // This is an (arbitrary) cutoff point for how large any single number on the complex plane will be allowed to grow.
Cheat_For_Speed_Flag = FALSE // Set to TRUE for a fast render, but with lower accuracy.
/////////////////////////////////////////

// Here we set the range and domain of the section of Mandelbrot we will be looking at.
// These setting values were chosen to include the full Mandelbrot set.
// But just as any two points on a number line have an unlimited number of points between them,
// we can zoom into the Mandelbrot simply by choosing smaller interval between the start and end points,
// and then incrementing by smaller amounts.
//
// To build on this program, you could allow the user to drag a frame across a section of the
// Mandelbrot set on the screen, and obtain new start and end points from that, so to render
// a new view based on those values. This would allow the user to zoom into the Mandelbrot set.
// Because this is only a demonstration of the complex-number functions, I did not implement that feature.

IF PictureHeight_in_Pixels > SCREENWIDTH-10 THEN SCREENWIDTH = PictureHeight_in_Pixels+10
IF PictureHeight_in_Pixels > SCREENHEIGHT-10; SCREENHEIGHT = PictureHeight_in_Pixels+10
CLEARSCREEN;SHOWSCREEN
SETSCREEN SCREENWIDTH,SCREENHEIGHT,FALSE
ENDIF

X_Pixels = PictureHeight_in_Pixels-1;Y_Pixels = PictureHeight_in_Pixels-1
Fieldlength = 3.0/2;FieldShift = 0.65
Mand_Start_X# = 0-Fieldlength-FieldShift;Mand_End_X# = Fieldlength-FieldShift//+Mand_Start_X
Mand_Start_Y# = 0-Fieldlength ; Mand_End_Y# = Fieldlength
Mand_Rez_X# = (Mand_End_X - Mand_Start_X)/X_Pixels // This is the incriment value of each X pixel.
Mand_Rez_Y# = (Mand_End_Y - Mand_Start_Y)/Y_Pixels // This is the incriment value of each Y pixel.

FOR CountX=0 TO X_Pixels;FOR CountY=0 TO Y_Pixels

// The Mandelbrot formula couldn't be easier. It is Z=Z^2+C, where both Z and C are complex numbers.
// It is odd at first to think of one number having two components, but complex numbers do. Every point on the complex plain represents
// a single number. The two components of that number give a horizontal position and a vertical position, like a grid.
// One horizontal axis is the old real number line you know and love.
// The vertical axis is the "imaginary" number line, which is at a right angle to the real number line.
// (Imaginary numbers are every bit as 'real' as counting numbers, they just are not found on the real number line.)
// These two components form a sort of address on the complex plane, having a real component along the horizontal axist,
// and an imaginary component along the vertical. These "address" are plugged into Z=Z^2+C.
//
// Z always starts off equal to zero, while the complex number C holds the current address for the pixel we are calculating for.
// Then we take the square of Z, add C and plug that back into Z. This is the new value of Z. C doesn't change.
// We repeat this process again and again, for however many itterations we wish. Then we at the final value of Z.
//
// Some values on the complex plane don't go very far from where they started. Some take off very quickly towards infinity.
// The rest sort of take their time in growing larger, but grow they do, at leasurely pace.
// There is no reason to wait until a Z gets to infinity, or anywhere close, to figure out how that complex number is acting.
// All we have to do is watch how quickly it exceeds a set number, say 1000 (our Magnitude number), then base the color we will
// paint the pixel for the position on that. This is how each pixel gets its color.

Z=Zero // Clear the values out of Z.
C.real = Mand_Start_X+Mand_Rez_X*CountX;C.imaginary=Mand_Start_Y+Mand_Rez_Y*CountY //C = the current location-point on the complex number plane.

ColorPixel(CountX,CountY,0) //All pixels which fail to reach Magnitude by the time we run all of our itterations get colored black.
//For effency, we will start out setting the pixel black, run the itteration loop and change the pixel color if we need to.
FOR Iter = 0 TO MaxIterations
SQUARECOMPLEX(Z,Z) // Z=Z^2
ADDCOMPLEX(Z,C,Z)  // Z=Z+C (so taken together theses two lines are Z=Z^2+C)

IF Cheat_For_Speed_Flag = TRUE
IF (ABS(Z.real) > Magnitude OR ABS(Z.imaginary) > Magnitude) THEN ColorPixelFlag = TRUE //Fast but causes frilled border artififact.
ELSE
IF SQR(POW(Z.real,2)+POW(Z.imaginary,2))>Magnitude THEN ColorPixelFlag = TRUE // Slow but accurate.
ENDIF

IF ColorPixelFlag = TRUE;ColorPixelFlag = FALSE;ColorPixel(CountX,CountY,Iter);BREAK;ENDIF //If yes, color pixel and abort loop.
//If no, continue iterations.
NEXT
// The 'cheat' If/Then line above, where I check magnitudes of the X and Y, does a decent job, but it
//  produces the frilly-edge artifact on the red boundary which you will see.
// For greater accuracy, set the Cheat_For_Speed_Flag to FALSE. The red edge will be smooth, but rendering takes seven times longer.
// That may not matter if you have a beefy graphics card.

NEXT;USEASBMP;SHOWSCREEN;NEXT //Next y-pixel; Next x-pixel

PRINT "Complex Numbers are Fun!",550,150

ENDSUB // CREATE_MANDELBROT

// ------------------------------------------------------------- //
// ---  ColorPixel  ---                                          //
// Colors current pixel the RGB color returned by Mandel_Color   //
// ------------------------------------------------------------- //
FUNCTION ColorPixel:X_grid,Y_grid,CyclesExecuted // The pixle color is determined by how quickly a location on the Imaginary Plane exceeded the
                                                 // maximum allowable magnitude. (How quickly the address headed towards infinity.)
SETPIXEL 10+X_grid,5+Y_grid,Mandel_Color(CyclesExecuted)
ENDFUNCTION // ColorPixel
// ------------------------------------------------------------- //
// ---  MANDEL_COLOR  ---
// Assigns RGB color based on the number of itteation cycles executed to exceed Magnitude.
// ------------------------------------------------------------- //
FUNCTION Mandel_Color: Height

LOCAL a,b,c

a=0;b=0;c=0

SELECT Height

CASE 1 TO 5;a=0;b=255;c=0
CASE 6 TO 7;a=255;b=0;c=0
CASE 8 TO 11;a=0;b=0;c=255
CASE 12 TO 16;a=255;b=255;c=255
CASE >16;a=255;b=0;c=0

DEFAULT; a=0;b=0;c=0;
ENDSELECT

RETURN RGB(a,b,c)

ENDFUNCTION // MANDEL_COLOR
 
#16
Hi, I've enjoyed reading the posts here in times past, but this is the first time I have needed advice. I hope someone can help.

I am currently well into the writing of an animation spread-sheet program, which treats animation frames and operations on them similarly to how spreadsheet functions operate on data cells. Each row of my spreadsheet contains a different filmstrip, each with a different layer or object for the composite final animation. All rows will be stacked on top of each other, like layers, for the final animation. You get the idea. So far so good.

Needless to say, I have a LOT of frames. I calculate that my memory will allow six filmstrips of 130 frames each, plus the final composite film strip, for a total of 910 frames. So far I have been crunching data using arrays extensively, and then copying individual frames to a workspace one-dimensional array from which to make a sprite to draw onto the spreadsheet cell. That is a lot of copying going on. Can it be avoided?

It occurs to me that the program would run much faster if I can make better use of the native GLbasic sprite handling functions. For example, SPRCOLL() could be used to detect blank frames for the purpose of setting the end pointers or detecting empty film tracks after the user deletes one or more frames. But to use the sprite handling functions, I need to use MEM2SPRITE(). Here we get to the horns of my dilemma.

With so many frames contained within so many filmstrip rows, each with a full sprite of data, it would be very difficult to manage lots and lots of single-dimensional arrays; yet MEM2SPRITE() seems to function only with single dimensional arrays. Is there a way to eat my cake and have it too?

I wrote the following bit of code to show the two approaches I have taken in trying to program around this limitation. Neither approach seems to work, but maybe I am missing something. That is what I would like advice on, please.

For the record, I am just a hobbyist when it comes to programing. I can manage most tasks I set myself with BASIC, but I am a rank amateur at C++, so I would like to stick with basic if at all possible.

Thanks for any advice you can give. Here is my demonstration code. -CW
Code (glbasic) Select

// Attempting MEM2SPRITE() work around.
// (Excuse the mousefont. I am trying to keep things simple. Please add a font for readability if you wish it.)

TYPE Track
GraphicData[10000] //100 X 100 sized frames (or sprites)
ENDTYPE

GLOBAL Filmstrip%[] AS Track
DIM Filmstrip[6]
// Note that for simplicity I have removed an entire hierarchy layer of complication (IE: 6 tracks, each 130 frames long,
// each frame containing an entire sprite worth of pixel data.) The simplified model is sufficient for the problem I am trying to solve.

LOCAL counter% = 0 // Count number of pixels set for later print statement.
FOREACH frame IN Filmstrip[];FOREACH pixel IN frame.GraphicData[];pixel = RGB(255,255,0);counter=counter+1;NEXT;NEXT

PRINT "All Frames in all 6 filmstrips filled with yellow. ",10,30
PRINT counter+" Pixels set.",10,60
PRINT "Attempting to create a sprite using a pointer in MEM2SPRITE(). PRESS KEY.",10,90
SHOWSCREEN;KEYWAIT

//Let's create a comparison sprite from a single-dimensional array to demonstrate that the mechanics are otherwise sound.
GLOBAL CS%[]
DIM CS%[10000]
FOREACH pixel IN CS[];pixel=RGB(0,255,0);NEXT
MEM2SPRITE(CS[],2,100,100)

////////////////////////////////////////////////////////
// This next bit is the point of the program.
// I am trying to get around the single dimensional array limitation of MEM2SPRITE() using a pointer.
// (I know, I know, arrays all pass pointers anyway, so why should MEM2SPRITE be so picky on this?
// Instead of a pointer to a single array, why not a pointer to a single array within a multidimensional array? Can it be done?)

//MEM2SPRITE(Filmstrip[2].GraphicData[],1,100,100) //The direct approach

ALIAS FramePointer AS Filmstrip[2]
// MEM2SPRITE(FramePointer.GraphicData[],1,100,100)   //Using a pointer as stand-in for Filmstrip[2], just in case MEM2SPRITE is syntax sensitive, for some reason.
//
// Neither approach will compile successfully. It seems GLbasic can't handle this, or am I missing something?
////////////////////////////////////////////////////////

CLEARSCREEN
ALPHATESTING 1 // Disable transparency, as I did not set Alpha when I filled the frames with color.
DRAWSPRITE 1,70,10;DRAWSPRITE 2,400,10
PRINT "Multi-Array Sprite",50,120;PRINT "Single-Array Sprite",375,120
PRINT "Press Key to Exit",220,150;SHOWSCREEN;KEYWAIT
END