Post your questions, comments, and code and I'll do my best to help answer all your questions.
I welcome all comments about the tutorial, positive and negative. You won't hurt my feelings one bit if you have a criticism to share. How else will I know how the tutorial needs to be improved?
I have a routine that tracks multiple FPS rates within a master FPS rate. I noticed with certain values that it fails. My son actually created the routine for me a few years back. I showed him what was going on and we tracked it to a floating point error.
For example. The result of x should be 1 but instead the value .9999999 is given:
f = 2 / 454
x = 227 * f
(2 is the target FPS, 454 is the global FPS, 227 is the current global frame number)
I've already created a work around for this. My son's code is too precise for what I need. He's tracking the exact moment the frame changes, whereas I simply need to know the alternate frame number within the master FPS. His code:
Fraction = TargetFPS / GlobalFPS
x = CurrentGlobalFrameNumber * Fraction
IF INT(x) <> INT(x - Fraction) THEN ... (report that a frame change happened)
All I simply need is INT(x) for my purposes but the possibility of a floating point error may still exist in QB64. Am I correct in assuming this?
client = _OPENCLIENT(FullIP) IF client THEN PRINT"Connected to Steve's Chat!"
server_active = ExtendedTimer + 300'server is now counted as being "active" for the next 5 minutes GET #client, , ChatLen
ChatLog = SPACE$(ChatLen) DO GET #client, , tempString
ChatLog = ChatLog + tempString _LIMIT30 LOOP UNTILLEN(ChatLog) >= ChatLen
INPUT"Enter your name =>"; nam SendMessage"/NAME:" + nam _KEYCLEAR'clear the input buffer, Steve, you big idiot! '_KEYHIT will still hold the name in that buffer as it's independent to INPUT!
NextPing = ExtendedTimer DO' main program loop
recieved$ = GetMessage ProcessInput recieved$ ' deal with any server command type messages IF recieved$ <> ""THEN' we got something from the clien _DEST TextArea IF TimeStamp THENCOLOR Yellow: PRINT"[" + TIME$ + "] ";: COLOR DefaultColor PRINT recieved$ ' it should just be a message of some sort END IF InputJunk
IFExtendedTimer > NextPing THEN'send a message to the server that we're still active SendMessage"/PING:"' that message is a simple PING
NextPing = ExtendedTimer + 30'and send this every 30 seconds so we don't disconnect. END IF
FUNCTIONExtendedTimer## 'Simplified version of the TimeStamp routine, streamlined to only give positive values based on the current timer. 'Note: Only good until the year 2100, as we don't do all the fancy calculations for leap years. 'A timer should work quickly and efficiently in the background; and the less we do, the less lag we might insert 'into a program.
DIM m ASINTEGER, d ASINTEGER, y ASINTEGER DIM s AS_FLOAT, day ASSTRING
day = DATE$
m = VAL(LEFT$(day, 2))
d = VAL(MID$(day, 4, 2))
y = VAL(RIGHT$(day, 4)) - 1970 SELECT CASE m 'Add the number of days for each previous month passed CASE2: d = d + 31 CASE3: d = d + 59 CASE4: d = d + 90 CASE5: d = d + 120 CASE6: d = d + 151 CASE7: d = d + 181 CASE8: d = d + 212 CASE9: d = d + 243 CASE10: d = d + 273 CASE11: d = d + 304 CASE12: d = d + 334 END SELECT IF (y MOD4) = 2AND m > 2THEN d = d + 1'add a day if this is leap year and we're past february
d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
d = d + (y + 2) \ 4'add in days for leap years passed
s = d * 24 * 60 * 60'Seconds are days * 24 hours * 60 minutes * 60 seconds ExtendedTimer## = (s + TIMER) END FUNCTION
I'll leave the host up and running all day, but I may not be around the whole time to chat or interact with anyone, and I don't guarantee that the server won't explode spontaniously and die a horrible death. But, at the moment, it seems stable with an client base of ONE person testing it. LOL!!
Okies... now I have TWO people testing it -- Steve and Steve2! Yay!!
Anyone want to take bets on how long it takes before this simple chat dies and has to be rebooted and restarted?
Started on this routine today for a friend who wants to make a menu pop on the screen with a little flair. Here's what I have so far. It just grows the image in with a little extra grow and shrink loop at the end, and then shrinks the image out. Posting here for any suggestions and improvements. Maybe there's a much better way to do the effect.
- Dav
Code: (Select All)
'imagepop.bas
'============
'Shows menu image on screen with a popup effect.
'Coded by Dav MAY/2024 with QB64PE v3.13.0
Screen _NewImage(1024, 680, 32)
'== make a sample image to use offscreen (REPLACE WITH YOUR OWN)
menu& = _NewImage(500, 500, 32) 'name the image
_Dest menu& 'point drawing commands to it
Cls , _RGB(255, 255, 255) 'main color of image
Line (10, 10)-(490, 490), _RGB(64, 64, 128), BF 'draw border
For y = 10 To 490 Step 5
Line (10, y)-(490, y), _RGB(0, 0, 0), B 'draw lines down screen
Next
_PrintMode _KeepBackground 'using this so printstring wont destroy background
For t = 1 To 200
_PrintString (Rnd * 425 + 10, Rnd * 460 + 10), "MENU" 'print something
Next
'===================
_Dest 0 'now point drawing back to main screen
'=== draw stuff on screen
For x = 10 To _Width - 10 Step 10
For y = 10 To _Height - 10 Step 10
Line (x, y)-Step(5, 5), _RGB(Rnd * 255, Rnd * 255, Rnd * 255), BF
Next
Next
'pop it out
PopImage "out", _Width / 2, _Height / 2, menu&
Sub PopImage (way$, x, y, image&)
Static PopImageBack& 'share this
xmax = _Width(image&)
ymax = _Height(image&)
_Display
If UCase$(way$) = "IN" Then
'== copy background first
PopImageBack& = _CopyImage(_Display)
'=== pop image on screen
xcount = 0: ycount = 0
Do
_PutImage (x - xcount, y - ycount)-(x + xcount, y + ycount), image&
xcount = xcount + 4: ycount = ycount + 4
If xcount > xmax / 2 Then xcount = xmax / 2
If ycount > ymax / 2 Then ycount = ymax / 2
If xcount >= (xmax / 2) And ycount >= (ymax / 2) Then Exit Do
_Limit 250
_Display
Loop
'=== make a little pop effect (grows and shrinks at end)
For highpop = 100 To 1 Step -20
For t = 1 To highpop Step 4
Cls
_PutImage (0, 0), PopImageBack&
_PutImage (x - xcount - t, y - ycount - t)-(x + xcount + t, y + ycount + t), image&
_Display
_Limit 200 + highpop
Next
For t = highpop To 1 Step -3
Cls
_PutImage (0, 0), PopImageBack&
_PutImage (x - xcount - t, y - ycount - t)-(x + xcount + t, y + ycount + t), image&
_Display
_Limit 200 + highpop
Next
Next
'Make sure it show normal at the end
Cls
_PutImage (0, 0), PopImageBack&
_PutImage (x - (xmax / 2), y - (ymax / 2)), image&
_Display
End If
If UCase$(way$) = "OUT" Then
'check if PopImageBack& exists here? <<
'unpop image here
xcount = xmax: ycount = ymax
Do
Cls
_PutImage (0, 0), PopImageBack&
_PutImage (x - xcount, y - ycount)-(x + xcount, y + ycount), image&
xcount = xcount - 4: ycount = ycount - 4
If xcount > xmax / 2 Then xcount = xmax / 2
If ycount > ymax / 2 Then ycount = ymax / 2
If xcount <= 0 And ycount <= 0 Then Exit Do
_Limit 200
_Display
Loop
'=== restore background
Cls
_PutImage (0, 0), PopImageBack&
_Display
End If
Ah, _SaveImage, my old friend! How I loves you. How I hates you. How your existance makes me want to wax profane like Shakespeare! "Why then, O brawling love! O loving hate! O any thing, of nothing first create! O heavy lightness, serious vanity, Misshapen chaos of well-seeming forms, Feather of lead, bright smoke, cold fire, sick health, Still-waking sleep, that is not what it is! This love feel I, that feel no love in this."
For ages and ages and ages, poor ole Steve worked hard to write and maintain a SaveImage Library for use with QB64 and QB64PE. https://qb64phoenix.com/forum/showthread.php?tid=20 <-- This library has been around forever and ever and ever, and poor ole Steve poured a lot of sweat and blood and tears and late nights fixing a nice library which works in QB64, in all screen modes (including text screens), to allow the user to save those screens (full or partial) in various image formats. I poured over GIF, BMP, PNG, JPG format specifications, sorted them out to the point where I could faithfully create them, and then I wrote simple code so an end-user could just do something like the following to save those screens:
SaveImage "My Screenshot.bmp"
And then... all in one night... back in version 3.9.... that all became obsolete!!
WAAAHHHHHHHH!!!
(And it doesn't even matter that I was the one who asked about it and helped get things going for the new command to be added to the core language. )
Back in v3.9, _SaveImage (wiki entry) was released, and it did everything that my library did (mostly) -- and then some!
Whereas my old library allows the user to save images in GIF, BMP, PNG, JPG formats, the new _SaveImage command allows users to quickly and easily save the screen in any of the following formats:
PNG: Saves the image as Portable Network Graphics format if no file extension is specified.
QOI: Saves the image as Quite OK Image format if no file extension is specified.
BMP: Saves the image as Windows Bitmap format if no file extension is specified.
TGA: Saves the image as Truevision TARGA format if no file extension is specified.
JPG: Saves the image as Joint Photographic Experts Group format if no file extension is specified.
HDR: Saves the image as Radiance HDR format if no file extension is specified.
Now, if you notice, all of these wiki entries have "if no file extension is specified" attached to the end of them. From talking to various folks, it appears that these extra few words are the main thing that confuse people in the wiki explaination of how to use this command. (Any suggestions for how to clarify things better, can always be submitted for Rho to take a look at, if anyone has any brilliant insight to word this better.)
Basically, the way _SaveImage works is very simple, with 3 possible parameters to it:
(Note that the last two parameters for imageHandle& and requirements$ are inside brackets and are thus optional parameters.)
The way these break down for us is rather simple.
_SaveImage <-- the command name. Always got to have a command name before any parameters! fileName$ <-- the name that we to save the image to, on our storage device. imageHandle& <-- this is the handle to the image that we want to save, in case it's not our current _DISPLAY requirements$ <--- *THIS* is what that "if no file extension is specified" is refering to.
fileName$ is NOT optional, as you can't save a file with no name.
fileName$ also takes precidence in how we save our file, IF YOU SPECIFY A VALID EXTENSION. For examples:
_SaveImage "foo.BMP" <-- This will create a BMP file, of the current _Display image. _SaveImage "foo.BMP", WorkScreen <-- This will create a BMP file, of whatever image is associated with the WorkScreen handle. _SaveImage "foo.BMP", , "JPG" <-- This will create a BMP file, of the current _Display image. This will ignore that last paramater as the file type is specified in the name (foo.BMP). (Notice I left that middle parameter blank, as it's optional.) _SaveImage "foo", , "JPG" <-- This will create a JPG file, of the current _Display image. Notice that the filename doesn't have any extension associated with it?
It's only when the filename has no extension that we use the 3rd parameter. After all, how silly would it be to have "PNG" files saved under the name "foo.QOI"??
And with that one clarification out of the way, there's really not much else to say about it. This is one of our simplest commands to learn, use, and master, in my opinion.
_SaveImage "My Screenshot.BMP" <-- 99.99% of the time, that's all someone needs to save the screen image. What can be any simpler than that??
As he didn't want to make aBIG DEAL ABOUT THINGS, we decidedto make a small announcement so everyone can welcome @luke back to the development team for QB64PE.
For those who aren't aware, Luke is also commonly known in the QB64 circles as flukiluke -- one of the key Team QB64 developers who helped keep the project up and going, before it was closed down for good and then we took over with the QB64 Phoenix Edition. After the closing of Team QB64, it was luke who recovered the old forums which RC had burnt down, and he's the person who's been hosting and keeping those up and available for everyone to look back on, whenever they might take a notion to do so.
And now, after a small break for college and work and life and eating nasty upside-down cakes (or whatever the heck they eat on the other end of the world), he's came back and rejoined the development team once again.
Welcome back home, Luke!
Everyone welcome him quietly. We don't want to scare him back off -- at least, not until he's churned out at least ANOTHER million lines of code for us!
Well, we can read multiple mice in Windows - see the attached code
plug in 2+ USB mice
make sure .h files are in program directory
compile subprogram 'readmicesub43.bas" (or run it, it will run and immediately close)
run the main program "readmicemain43.bas"
try moving around the different mice on your PC, you should see letters move around the screen
try clicking left and middle mouse buttons to hear sounds
to quit, right click any mouse
However I'm not sure about reading the absolute position of the cursor - it tracks movement pretty good using dx/dy, but you can't quickly move a mouse and have the position jump immediately to where the mouse cursor should be. There is a value the subprogram reads that I thought might be the absolute position but doesn't seem to be. Any ideas? Also how to read the scroll wheel?
I'm also not sure how to detect keypresses in the current program. Normal methods of reading the keyboard like _BUTTON, _KEYHIT and _KEYDOWN from the main loop in the subprogram (which has the focus) don't seem to work. Maybe the keyboard needs to be read using Raw Input? And as long as we're using the Raw Input API to read the keyboard, can we read seperate input from multiple keyboards, like we do with mice? I found a bunch of information on using the Raw Input API to read keyboard input:
but this stuff is way over my head, and I would need some help translating this into QB64PE.
With everyone's help I was able to get the mouse mostly working, so the keyboard should be possible too.
If anyone is interested in giving this a look, that would be great.