Get Pixel Color on MO6

Cette catégorie traite de développements récents pour nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Carl, Papy.G, fneck

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Get Pixel Color on MO6

Message par Garland » 10 juin 2019 17:42

Hi everyone.

I need to read a screen pixel value in asm so i would use the routine at $14 (GETP) - the only issue is i don't know why it doesn't seem to work.
It should take X and Y as coordinates and return the value in accumulator B.
So as far as i read it's enough to write:

LDX #100
LDY #150
CALL $14

To get the value of coords 100,150 in B. I'm trying to execute this in basic and it puts 3A while i should i expect 01 instead … ? What i'm missing here?

Thank you!

Image

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 10 juin 2019 18:54

What you are trying to do is just the basic command: Point(x,y).

How do you get the return value ? EXEC doesn't return any meaningful value. To get a value from asm to basic you can:
1) put that value in a defined memory address and read it back in basic with a PEEK, or
2) use the DEFUSR command which provides a mechanism to return a value (integer, float, string IIRC) to the basic.

From what I see, it seem you are getting the value from a step by step execution of the code. Unfortunately the B value you observe is one deep inside the routine or in an interrupt, not the one returned. Better put a breakpoint at the RTS ($4129) and observe B when execution reaches that point.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 10 juin 2019 20:47

__sam__ a écrit :
10 juin 2019 18:54
Unfortunately the B value you observe is one deep inside the routine or in an interrupt, not the one returned. Better put a breakpoint at the RTS ($4129) and observe B when execution reaches that point.
Thank you Sam, yes, Putting it at specific address solved some issues:

LDX #73
LDY #90
CALL $14
STB $5000

Then in BASIC:

PSET (73,90),1
EXEC &H4000

PRINT "";PEEK(&H5000)
1

This works but PEEK is slow. So i'm trying to pass it across the X register. Now with USR function you can store from the asm an integer in 2,X which will be the resulting value in BASIC call. I already did this before with other asm routines and it worked so i can't get what's different this time :D

It should be just a

LDX #73
LDY #90
CALL $14
LDA #02 <-- return type
STD 2,X <--- put code

And then

PSET(73,90),1
DEF USR1=&Haddress
N%=USR1(whatever)

N% should be 1 at this point...

I also tried to PSHS, PULS the registers (since $14 involves S) but didn't work. Calling N%=USR1(num) ends with N% always equal to num so apparently the value in 2,X isn't updated.

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 10 juin 2019 21:30

Beware, reg D is the concatenation of reg A and reg B, so your LDA #2 trashes the reg D. I think you should to it like this:

Code : Tout sélectionner

LDX #73
LDY #90
CALL $14 ; result in B
SEX      ; sign-extend B into A:B=D
STD 2,X  ; store it into basic
LDA #2   ; tell the basic that the result is integer
RTS      ; return to basic
Another possibility which is faster than PEEK or even USR is to use VARPTR() to get the address of a variable, patch the ASM so that it writes B into the LSB of that variable:

Code : Tout sélectionner

Asm:
$4320 LDX #73
$4323 LDY #90
$4327 CALL $14
$4329 STB $5000
$432D RTS

Basic:
COL% = 0 ' declare variable
ADR = VARPTR(COL%)+1 ' get LSB address
' PATCH ASM
POKE &h432A, ADR@256 ' integer division to get MSB of address
POKE &h423B, ADR AND 255 ' bit mask to get LSB of address

PSET(73,90),1
? COL% '---> 0
EXEC &h4320
? COL% '---> 1
You can extend this so that X and Y regs gets their value from 2 basic variables :)
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 10 juin 2019 21:47

Thanks Sam.

You said this is faster than USR, but POKE isn't a little slow? I was thinking to pass col,row in the USR function, maybe with a double precision value? In this way i would avoid POKE but i don't know if is worth the effort.

Also, this code:

Code : Tout sélectionner

		 LDX #73
		 LDY #90
		 CALL $14 ; result in B
		 SEX      ; sign-extend B into A:B=D
		 STD 2,X  ; store it into basic
		 LDA #2   ; tell the basic that the result is integer
		 RTS      ; return to basic

I tried to plant it in $4320 then i made:

Code : Tout sélectionner

PSET (73,90),1
DEF USR1=&H4320
N%=USR1(0)
PRINT N% 
but N% is still 0 ...
Modifié en dernier par Garland le 10 juin 2019 21:53, modifié 2 fois.

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 10 juin 2019 21:51

POKE is slow, but you use it only once in the init of the program to bind the COL% and the ASM code. Then later, every time you call EXEC &h4320, the COL% variable is updated with the pixel value without need for PEEK or POKE anymore.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 10 juin 2019 21:58

About N%=0: it's my bad. I haven't preserved the X reg. The correct code is:

Code : Tout sélectionner

		 PSHS X   ; backup X reg onto stack
		 LDX #73
		 LDY #90
		 CALL $14 ; result in B
		 SEX      ; sign-extend B into A:B=D
		 PULS X   ; restore X reg from stack
		 STD 2,X  ; store it into basic
		 LDA #2   ; tell the basic that the result is integer
		 RTS      ; return to basic
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 10 juin 2019 22:00

Yep, so in this case you have to preserve X reg, quite clear now. The addess swap trick is stunning for a newbie like me :) I'm always amazed about how many things i can learn here ;)
Thank you again!

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 11 juin 2019 02:50

So it seems to work if i use this code:

Code : Tout sélectionner


		 ORG $4320	
        
                 * Location: $4320
		 
		 * Get color
		 PSHS X     ; backup X reg onto stack
		 LDX $2B01  ; to be modified in basic  ($4323,24)
		 LDY $2B08  ; to be modified in basic  ($4327,28)

		 CALL $14   ; result in B
		 SEX        ; sign-extend B into A:B=D
		 PULS X     ; restore X reg from stack
		 STD 2,X    ; store it into basic
		 LDA #2     ; tell the basic that the result is integer
		 RTS        ; return to basic
 		

		 END	 


BASIC:

Code : Tout sélectionner


X%=100:Y%=150

ADR = VARPTR(X%) ' get LSB address
POKE &H4323, ADR@256 ' integer division to get MSB of address
POKE &H4324, ADR AND 255 ' bit mask to get LSB of address

ADR = VARPTR(Y%) ' get LSB address
POKE &H4327, ADR@256 ' integer division to get MSB of address
POKE &H4328, ADR AND 255 ' bit mask to get LSB of address

DEF USR1=&H4320

CLS : PSET(X%,Y%),1
N%=USR1(0)

PRINT N%

The thing which made me crazy (once again, damn 16bit registers) is the byte placement.

Note that i used VARPTR(X%) and not VARPTR(X%)+1 like in your example, in order to have LDX getting 0064 and not 64 as value, is that right?


Thank you :)

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 11 juin 2019 07:41

Garland a écrit :
11 juin 2019 02:50
Note that i used VARPTR(X%) and not VARPTR(X%)+1 like in your example, in order to have LDX getting 0064 and not 64 as value, is that right?
Yes: since X is a 16 bit reg, you should point to the MSB of X%. Therefore, no "+1" to add.

One question: why don't you use N%=POINT(X%,Y%) to get the pixel color directly in plain basic ?
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 11 juin 2019 13:55

Because i wanted to see if POINT(X,Y) was doing something more in comparison to this code and it seems not.

My purpose was to improve speed for some tasks which are particularly slow in basic, like drawing, getting input and checking collisions. Sometimes, instead pure ASM, you want to prefer the confort of basic but you don't want to lose too much speed for this. So i made a routine for sprite drawing and input checking and they worked beautifully, but i faced a new slowdown on collision checking.

I thought the pixel color checking was the most accurate way to accomplish the task, and i noticed how POINT slow was. Under the hood executes the routine $14 and as you know it has to take the x y and convert to raw address, mask pixels, swap $A7C0 to get form/color and so on, but as a tradeoff you can check the exact pixel in the octet so its useful. I didn't use monitor routines for sprites and input and i can see the difference. I checked the code of $14 and i can't find so much shortcuts which i could apply.

Now i'm looking for something faster, but i'm afraid isn't easy. If you want the right pixel a in octet by passing X and Y screen coords, this seems the only way (address conversion, pixel masking, mode swap). I should rethink the logic to gain some speed… maybe checking an entire octect by passing the address directly, although it sounds cheap … if you have suggestions, i'll appreciate :D

Thank you again!
Modifié en dernier par Garland le 11 juin 2019 14:56, modifié 1 fois.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 11 juin 2019 14:12

Here's a little demo - this is all basic except the drawing and input part. The speed is enjoyable if you consider there's the basic interpreter under the hood. When the character moves left it doesnt check collisions, when the character moves right it does. Look at the difference :D

The collision checking here is just a couple of POINT instructions (one for head, one for feet), so let's see if i can improve this task too.


__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 11 juin 2019 23:02

I pressume you do POINT() not on any pixel, but on coordinate of kind (8*I%+C1%, 8*J%+C2%) [C1% and C2% being fixed]. In that case it is quite easy and fast to get the coordinate in ASM. Even if you need POINT(I%,J%) for any 0<=I%<320 and 0<=J%<200, an ASM implementation is quite easy to write and pretty fast. Here is a sketch of such implementation (not tested) to be used with DEFUSR :

Code : Tout sélectionner

  PSHS X ; preserve result reg

  LDU #$A7C0 
  LDA ,U
  ANDA #$FE ; clear bit 0
  STA ,U ; make video point to "color" data

  LDD $yyyy; Y coordinate (to be bounded to a basic variable "J%" via VARPTR)
  LDA #40
  MUL    
  TFR D,X  ; X = J%*40
  
  LDD $xxxx ; X coordinate (to be bounded to a basic variable "I%" via VARPTR)
  LSRA
  TFR B,A ; A=LSB of I%
  RORB
  LSRB
  LSRB  ; B = I%/8
  ABX   ; X = ptr to video ram (= I%/8 + J%*40)

  LDB ,X ; B=color pair at (I%,J%)
  
  INC ,U ; switch video bank to get "FORM" data
  
  LDU #TAB ; mask-tab
  ANDA #7  ; A = I% MOD 8 
  LDA A,U  ; get bit MASK
  ANDA ,X ; check if pixel is on/off
  BEQ LBL ; if pixel off ==> keep low nibble (notice it can be a BNE.. I haven't checked the ordering of the color pair)
  LSRB	; pixel on ==> get top nibble
  LSRB
  LSRB
  LSRB
LBL:
  PULS X ; restore result ptr
  CLRA
  ANDB #15 ; isolate nibble
  STD 2,X ; write color into result for basic  
  LDA #2 ; tell basic that result is integer
  RTS ; return to basic
TAB:
  FCB 128,64,32,16,8,4,2,1
It returns a the color of pixel at (I%,J%) as an integer between 0 and 15. This mean it doesn't indicate the fg or bg status of the pixel. It can be modified to do so, but it'll be slower and usually one only needs the pixel color regardless of it being bg or fg color I presume.

I hope it'll help you.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Garland
Messages : 17
Enregistré le : 25 oct. 2018 19:40

Re: Get Pixel Color on MO6

Message par Garland » 12 juin 2019 01:11

Well, i just need the bg color, so if its value is neg there's no collision. However, with you code i could store the same value for two different colors to manage transparent pixels (like those around the trees) while keeping the collision check. Thanks!

A question: sometimes, if i have LDD $xxxx, after the poke i see LDD #$xxxx, so 'm guessing why it puts the value on immediate addressing or not.

PS : of course your code worked at first blind attempt ♥

__sam__
Messages : 4589
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Get Pixel Color on MO6

Message par __sam__ » 12 juin 2019 07:27

I don't understand the question.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Répondre