News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Double buffer in mode 13H

Started by popcalent, February 07, 2024, 04:46:28 PM

Previous topic - Next topic

popcalent

Quote from: NoCforMe on February 09, 2024, 10:40:34 AMWhy don't you try my suggestion and see what it does for you? (Including inlining your PUT_PIXEL_IN_BUFFER code.)
Will do when I have a chance. Probably later tonight.

Quote from: NoCforMe on February 09, 2024, 10:40:34 AMIf you're moving an even number of bytes, then by all means use MOVSW instead of MOVSB. Take every advantage.
I'm copying a buffer the size of the 320x200 screen, so yes, it's an even number of bytes.

daydreamer

Quote from: popcalent on February 09, 2024, 08:09:56 AMThanks! Is this also taking care of the keyboard lag when using arrow keys to move a sprite?
no idea,I am spoiled by running Dosbox emulation on 3+ghz cpu,guess its capable of ca pentium cpu speed
depending on what kind of game you can make,simple physics engine ala moonlander and asteroids kind of control ,it always
add x,xspeed
add y,yspeed each frame
keyboard controls indirectly accelerate/decelerate xspeed and yspeed 
if you have fpu,might be faster to copy with fld/fstp 10 bytes at a time

my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

popcalent

Quote from: daydreamer on February 10, 2024, 04:08:26 AMno idea,I am spoiled by running Dosbox emulation on 3+ghz cpu

I'm talking about the lag that happens after you press a key on any computer, even a modern one. For instance, you press 'a' on your favorite word processor and don't release, then just one 'a' appears on screen, and after a second of doing nothing the screen starts getting filled with a's until you release.

On a game, you would press an arrow key, the sprite would take a step towards that direction, stop for a second, then start walking. Of course, professional games don't do that, you press a key and the sprite starts walking without pausing for a second after the first step.

daydreamer

Quote from: popcalent on February 10, 2024, 07:26:26 AM
Quote from: daydreamer on February 10, 2024, 04:08:26 AMno idea,I am spoiled by running Dosbox emulation on 3+ghz cpu

I'm talking about the lag that happens after you press a key on any computer, even a modern one. For instance, you press 'a' on your favorite word processor and don't release, then just one 'a' appears on screen, and after a second of doing nothing the screen starts getting filled with a's until you release.

On a game, you would press an arrow key, the sprite would take a step towards that direction, stop for a second, then start walking. Of course, professional games don't do that, you press a key and the sprite starts walking without pausing for a second after the first step.
I use lowlevel in al,60h keyboard port and combine it with simple physics
in al,60h
         
          .IF al== VK_LEFT
            mov middx,-3
            mov middy,0
            .ENDIF
           .IF al==VK_RIGHT
            mov middx,3
            mov middy,0
            .ENDIF
            .IF al==VK_UP
            mov middy,-640
            mov middx,0
            .ENDIF
            .IF al==VK_DOWN
            mov middy,640
            mov middx,0
            .ENDIF
            cmp al,1
cmp al,1 =escape key =exit game loop
I have written a VK_codes.asm files with equates compatible with windows keycodes to make it easier to port code between windows and DOS 16 bit
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

NoCforMe

So how are you accessing the keyboard in your program?

If you're using the DOS INT 21h interface, well, there's your problem; that's a high-level interface with lots of latency (time delay).

Your other choices are:
  • The ROM BIOS keyboard interface (INT 16h), which gives you low-level access to the keyboard. One of the functions here gives you an immediate status report on whether a keystroke is available, and what that keystroke is.
  • Intercepting the keyboard hardware interrupt (INT 9) directly, which will give you an immediate notification anytime a key is depressed.
None of these are very hard to implement.
Assembly language programming should be fun. That's why I do it.

sinsi

Have a 128-byte table for keys and hook int 15h, AH=4Fh. The INT 9 code reads the scan code from port 60h and calls this function. Set or clear the byte in the array depending on whether it's a make code, then your main loop can just check the array for keys down. Easier then hooking INT 9 and having to worry about LEDs and weird key codes (like SysRq).
🍺🍺🍺

NoCforMe

Are you sure about INT 15h? My book shows that as the cassette interface.
It's been a long time since I used any of that stuff, so I may be missing something here. Is AH=4FH a keyboard function?

I was thinking that hooking INT 9 would only involve peeking at the keycode, setting flags for certain keys only, then simply passing the request on to the real INT 9 handler. Basically a passive handler.
Assembly language programming should be fun. That's why I do it.

sinsi

🍺🍺🍺

NoCforMe

#23
Ah, nice clean interface there. That sounds like the way to go.

Invoked for each keystroke by the ROM BIOS's Int 09h keyboard
interrupt handler.
 
Input              Output
 
AH = 4Fh           If scan code consumed
AL = Scan code        Carry flag: clear
 
                   If scan code not consumed
                      Carry flag: set
                      AL = Unchanged or new scan code
Assembly language programming should be fun. That's why I do it.

popcalent

Quote from: daydreamer on February 10, 2024, 07:42:14 AMI use lowlevel in al,60h keyboard port and combine it with simple physics
in al,60h

There's still a problem with IN AL, 60h. If the user goes too fast with his fingers (which is pretty common) and presses another arrow key before releasing the current one, the sprite stalls.

I'm thinking about implementing a two-level stack. When the user presses an arrow key, the program pushes a corresponding value into the stack (for instance, UP=1, DOWN=2, etc) , when the user releases an arrow key, the program pops the corresponding value out of the stack.

An example sequence would be this:

1) User doesn't push any arrow key. Stack is 00. Sprite doesn't move.
2) User pushes right arrow key. Stack is 0R. Sprite moves to the right.
3) User pushes left arrow key without releasing right arrow key. Stack is RL. Sprite moves to the left.
4) User releases right arrow key without releasing left arrow key. Stack is 0L. Sprite still moves to the left.

An alternative to step 4:
4) User releases left arrow key without releasing right arrow key. Stack is 0R. Sprite moves to the right.

I've done this with C before, and it works "most" of the time. Sometimes, you release the keys, and the sprite is stuck walking. I guess it happens when you release the key while the code is doing something else and can't register the release. I guess the solution is to do it through an interrupt. But perhaps it's not necessary in ASM since it's faster than C.




NoCforMe

#25
Try hooking INT 15h as sinsi suggested; that might take care of that latency problem.

This code should do the hooking part:
OldINT15Vector LABEL DWORD
  OldINT15off DW ?
  OldINT15seg DW ?

PUSH ES ;Save segment reg.
XOR AX, AX ;Point to "zero segment".
MOV ES, AX
MOV BX, 15h * 4 ;Address of INT 15h vector.
MOV AX, ES:[BX] ;Get offset.
MOV OldINT15off, AX
MOV AX, ES:[BX + 2] ;Get segment.
MOV OldINT15seg, AX

CLI ;Disable interrupts.
MOV AX, OFFSET INT15handler
MOV ES:[BX], AX ;Plug in new offset.
MOV AX, CS ;Get our code segment.
MOV ES:[BX + 2], AX ;Plug it in.
STI ;Re-enable interrupts.
POP ES ;Restore segment reg.
. . .

INT15Handler PROC

CMP AH, 4Fh ;We're only interested in this subfunction.
JNE passon

; Set your flags or whatever here;
; key scan code is in AL.

passon: JMP FAR PTR OldINT15Vector ;Go to the original INT 15 handler.

INT15handler ENDP
Assembly language programming should be fun. That's why I do it.

sinsi

QuoteThere's still a problem with IN AL, 60h. If the user goes too fast with his fingers (which is pretty common) and presses another arrow key before releasing the current one, the sprite stalls.
Are the arrow keys being used as a toggle? For example, when you press the right arrow key the sprite moves right, what happens when the key is released? Does the sprite keep moving or stop?
🍺🍺🍺

popcalent

Quote from: sinsi on February 12, 2024, 11:51:00 AM
QuoteThere's still a problem with IN AL, 60h. If the user goes too fast with his fingers (which is pretty common) and presses another arrow key before releasing the current one, the sprite stalls.
Are the arrow keys being used as a toggle? For example, when you press the right arrow key the sprite moves right, what happens when the key is released? Does the sprite keep moving or stop?
Not as a toggle, but as a momentary switch. When the key is released, the sprite is supposed to stop.


I implemented a two level stack to prevent this from happening. This is similar to the 128-key table you proposed. This solves the problem with the user switching keys too fast. The problem now is that, most of the time, the sprite stops when the key is released, but sometimes it keeps moving. I'm not handling this as an interrupt (that's my next step), but as a procedure. My guess is that there are times the user releases a key, but the program is doing something else and doesn't register the release.

NoCforMe

Welcome to the world of tricky timing.

I think hooking interrupts is the way to go for you. All the interrupt hook will do is set a flag or two; it'll be up to your other code to check these flags--frequently!--to figure out what state it should be in.

I have confidence that you'll figure this out.
Assembly language programming should be fun. That's why I do it.

popcalent

Quote from: NoCforMe on February 12, 2024, 09:14:51 AMTry hooking INT 15h as sinsi suggested; that might take care of that latency problem.

This code should do the hooking part:

So, I had CALL CHECK_KEYBOARD first thing in the main loop. The first thing in this subroutine is IN AL, 60h. Then, depending on what was in AL, do this or that. And that worked most of the time except for the few cases where I released a key and the sprite got stuck moving.

I put the code to hook up the handler in a subroutine and I call the subroutine before the main loop. I basically copied your code. Then, in the interrupt handler, I copied your code and I added CALL CHECK_KEYBOARD between JNE passon and passon: JMP FAR PTR OldINT15Vector. Inside the CHECK_KEYBOARD subroutine I deleted the IN AL, 60h, and left everything else the same.

I made it this way because I didn't want to cut and paste large chunks of code to avoid possible mess-ups. However, the program is now not responding to any key presses. It's basically stalled.