Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Another strange thing related to the "graphics overwriting"
#2
apenao Wrote:I have polished a bit my sprite routine, writting it in just one file and erasing repeated code (it worked OK up to this point) and adding a new subroutine to set the background colour of the playing area. Wheter I use or not this routine (and even if I take it out of the sprite routine file and copy it in any part of the main program code) its causing the graphics behave strangely.

When I'm drawing the "show room" (the only one atm, where I'm trying the graphics and the movements) I call (via Gosub) the routines drawing the different parts, i.e.:
GOSUB ESQUINA -- DRAWS THE CORNERS
GOSUB HABITACINESCONPUERTA -- DRAWS THE "WALLS" AND THE DOORS

When I draw the decoration parts (i.e. a carpet, or different floor designs) I see one of the coordinates of the sprites is changed:

If I draw the carpet (GOSUB ALFOMBRA), then the transparent window has its Y coordinate changed, whatever the correct value is.

If I draw the star (GOSUB ESTRELLA), the main sprite's X coordinate is changed.
If I let the GOSUB ESTRELLA, I don't notice anything special. :?: If I use GOSUB ALFOMBRA, then the moving sprite gets corrupted.
It seems something is corrupting the stack frame, but I don't know what is it. I will investigate it further...

What I want to make clear is that those seems to be collateral effects, and might not be related to PLOT/DRAW at all, but for example, to stack or heap corruption. I see you use much inline asm blocks and gosubs, and this is not a good idea. You should make your routines directly callable from BASIC instead. I suggest you to try convert them using this:
  • If the function takes a single parameter, just use SUB FASTCALL xxx(param as..) scheme. The parameter will came in A register (if it is ubyte), HL if it's 16 bits, HLDE if it's 32 bits and A BCDE if it's FLOAT (like ZX Spectrum ROM). You can use RET at any point inside a FASTCALL sub. If you use FUNCTION, it's the same, but those registers will be also used to get the RETURN VALUE.
  • If the function takes more than one parameter, then it's better to use the normal (STDCALL) scheme. But guessing parameter addresses might by hard. So let the compiler TELL YOU.
Since you can tell the compiler to generate ASM, you can get the parameter addresses, creating a dummy SUB and getting it's asm:
Code:
SUB dummyTest(param1 as Ubyte, param2 as Uinteger)
DIM b as Uinteger
param1 = 1
param2 = 2
b = 5
END SUB
Compiling with zxb -A test.bas will create test.asm, which reads:
Code:
...
29 _dummyTest:
30     push ix
31     ld ix, 0
32     add ix, sp
33     ld hl, 0
34     push hl
35     ld (ix+5), 1
36     ld (ix+6), 2
37     ld (ix+7), 0
38     ld (ix-2), 5
39     ld (ix-1), 0
40 _dummyTest__leave:
41     ld sp, ix
42     pop ix
43     exx
44     pop hl
45     pop bc
46     ex (sp), hl
47     exx
48     ret
This is your SUB compiled. Notice now what's happening. Line 35 stores 5 at (ix + 5). So (ix + 5) if addr of param1 (you can read and write at any param address). And param2 is (ix+6) (Low byte) and (ix+7) (high byte). Local variable b is at (ix - 2) (low byte) and (ix - 1) (high byte). Notice IX + n are used for parameters and IX - n for local vars.

WARNING: Unlike FASTCALL subroutines, you can't return with RET from an STDCALL SUB or FUNCTION. You must clean and restore the stack frame, so to return you must JUMP to _dummyTest__leave.

Now you can start an ASM... END ASM block inside the subroutine, using the (ix+n) addresses to get the values passed by the caller. This is the way the compiler works, and it's the way you should too. When you write code outside the subroutines, the compiler might move it to another location (even with optimization disabled). In fact, SUBs and FUNCTIONS are moved to the end of the program, before the variables memory zone.
Reply


Messages In This Thread

Forum Jump:


Users browsing this thread: 2 Guest(s)