News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_mr_lou

sMIDP2lib for SDCC

Started by mr_lou, 17:43, 20 December 11

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

mr_lou

Ok, this thread is about a new idea for a C library to be used with SDCC for CPC development.
I've named the library sMIDP2lib because it is based on the J2ME MIDP2.0 API.

The project is described here:
http://www.cpcwiki.eu/index.php?title=SMIDP2lib_for_SDCC

This thread is about the building of this library, and will contain various source-code for the various routines needed.

I imagine this source-code will come from all forum members. Therefor you'll have to follow a few ground rules. So please go read the project-page in the above link before contributing. It contains all the info you'll need, including guidelines, rules decided so far, and a description of each method we'll be putting into the very first initial version. Thanks!

arnoldemu

I read about the double buffer.

To handle it the way midp does it, then you don't physically exchange the screen using the hardware.
&c000-&ffff is always visible, &4000-&ffff is always back buffer (examples).

You always draw to &4000-&ffff, and a "dirty" buffer knows which part of the screen you modified. (perhaps it's just a simple which 8x8 cell was modified), so 1 bit per cell is enough to describe the changes.

flushGraphics, simply uses the "dirty" buffer to decide which parts of the visible screen are actually updated, and all updates are done a cell at a time.

This is the way double buffering is done on most 48k spectrum games.

it doesn't avoid tearing, but it does solve your problem.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

mr_lou

Yes you're right. It would solve the problem, but kinda create another.
It might be ok though. Not sure. Depends on how fast the drawing can be done of course. Would really like to avoid the tearing.

sMIDP2lib for SDCC is not about creating a library that does exactly what MIDP2.0 does behind the screen though. It should merely act the way MIDP2.0 does, meaning it should just produce the same visual result.
That's why I thought the fastest screen-update would be to switch between screens. But then I have the problem described. So it's quite possible it'll end up being solved like you suggest. Unless some genius comes up with some other brilliant solution...

I've been trying for a few hours now to come up with something clever without luck.

mr_lou

Ok. I've spent a lot of time trying to come up with something clever, and have given up for now.

The way I see it, we have two options for this double-buffering issue.

1) We do the double-buffering like arnoldemu describes instead of how it's described on the project-page.
This will let us keep getRGB() and drawRGB(), which will most probably be very useful on the CPC. (I rarely use them in my J2ME stuff though).

2) We keep the double-buffering the way it's described on the project-page.
This will render getRGB() and drawRGB() kind of useless.


Basically the difference between the two options are, that option 1 lets you update only parts of the screen, while option 2 forces you to redraw the entire screen each frame.
While option 2 is the most commonly used procedure for J2ME developers, I imagine option 1 might be very much faster?

I can't make up my mind which option I prefer. On the one hand it would be optimal for portability from J2ME to CPC to go with option 2. On the other hand, I suspect that might be too slow. And going with option 1 wouldn't make it a problem for portability from CPC to other platforms.

So I need your opinion on this. What do you think?

demoniak

New start for the library  :)
void initGfxLib() {
__asm
        LD      BC,&BC01
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg1 = 32 (256 pixels width)
        OUT     (C),C
        LD      BC,&BC02
        OUT     (C),C
        LD      BC,&BD2A                ; Center the screen horizontally
        OUT     (C),C
        LD      BC,&BC06
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg6 = 32 (256 pixels height)
        OUT     (C),C
        LD      BC,&BC07
        OUT     (C),C
        LD      BC,&BD22                ; Center the screen vertically
        OUT     (C),C
        LD      DE,&C000
        JR      InitGfxLibDone
TabPen0:
        DB      &00,&77,&00,&BB,&00,&DD,&00,&EE
        DB      &80,&77,&40,&BB,&20,&DD,&10,&EE
        DB      &08,&77,&04,&BB,&02,&DD,&01,&EE
        DB      &88,&77,&44,&BB,&22,&DD,&11,&EE
TabPen:
        DS      2
InitGfxLibDone:
__endasm;
}

void setColor(unsigned char color) {
color;
__asm
        LD      A,(IX+4)
        AND     3
        ADD     A,A
        ADD     A,A
        ADD     A,A
        LD      HL,TabPen0
        LD      B,0
        LD      C,A
        ADD     HL,BC
        LD      (TabPen),HL
__endasm;
}

void drawLine(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2) {
x1;x2;y1;y2;
__asm
        LD      A,(IX+10)
        CP      (IX+6)
        JP      Z,drawLigneHor
        XOR     A
        LD      H,A
        LD      D,A
        LD      E,(IX+4)               ; x1
        LD      (drawLineX1+1),DE
        LD      L,(IX+6)                ; y1
        LD      (drawLineY1+1),HL
        LD      A,(IX+8)                ; x2
        LD      C,A
        LD      (drawLineX2+1),A
        LD      A,(IX+10)                ; y2
        LD      (drawLineY2+1),A
        SUB     L                       ; y2-y1
        JR      NC,drawLine2
        NEG
drawLine2:
        LD      E,A                     ; =absy
        LD      A,(drawLineX1+1)
        SUB     C                       ; x1-x2
        JR      NC,drawLineDy
        NEG
drawLineDy:
        SUB     E                       ; A = absx-absy
        LD      A,&EB                   ; &EB = EX DE,HL
        JR      C,drawLine3
        LD      A,(drawLineY2+1)
        LD      (drawLineX2+1),A
        LD      A,C
        LD      (drawLineY2+1),A        ; SWAP x2 and y2
        LD      A,(drawLineX1+1)
        LD      B,A
        LD      A,(drawLineY1+1)
        LD      (drawLineX1+1),A
        LD      A,B
        LD      (drawLineY1+1),A        ; SWAP x1 and y1
        XOR     A                       ; &00 = NOP
drawLine3:
        LD      (drawLineExchg),A
        LD      A,(drawLineY1+1)
        LD      E,A
        LD      A,(drawLineY2+1)
        SUB     E
        JR      NC,drawLine4
        LD      A,(drawLineY2+1)
        LD      (drawLineY1+1),A
        LD      A,E
        LD      (drawLineY2+1),A        ; SWAP y1 and Y2
        LD      A,(drawLineX1+1)
        LD      B,A
        LD      A,(drawLineX2+1)
        LD      (drawLineX1+1),A
        LD      A,B
        LD      (drawLineX2+1),A        ; SWAP x1 and x2
drawLine4:
        LD      A,(drawLineX1+1)
        LD      E,A
        LD      A,(drawLineX2+1)
        SUB     E
        LD      A,&35                   ; &2B = DEC (HL)
        JR      C,drawLine5
        LD      A,&34                   ; &23 = INC (HL)
drawLine5:
        LD      (drawLineXincr),A
        LD      A,(drawLineY1+1)
        LD      E,A
        LD      A,(drawLineY2+1)
        SUB     E
        LD      E,A                     ; DE = dy
drawLineX2:
        LD      HL,0
        LD      A,(drawLineX1+1)
        SUB     L                       ; x1-x2
        JR      NC,drawLine6
        NEG
drawLine6:
        LD      L,A
        ADD     HL,HL
        LD      (drawLineBincr+1),HL
        SBC     HL,DE
        LD      (drawLineDelta+1),HL
        SBC     HL,DE
        LD      (drawLineAincr+1),HL
        LD      HL,(drawLineY1+1)
        DEC     HL
        LD      (drawLineY1+1),HL
        LD      HL,(TabPen)
        LD      (drawLinePen+1),HL
drawLineY1:
        LD      HL,0
        INC     HL
        LD      (drawLineY1+1),HL
        EX      DE,HL                   ; DE = y1
drawLineY2:
        LD      HL,0
        SBC     HL,DE                   ; HL = y2 - y1
        JP      C,drawLineDone
drawLineX1:
        LD      HL,0                    ; HL = x1
drawLineExchg:
        DB      0                       ; NOP or EX DE,HL
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        ADD     A,A
        AND     C
        LD      D,A                     ; D = NumPixel * 2
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      L,H
        LD      H,0
drawLinePen:
        LD      BC,0
        ADD     HL,BC
        LD      C,(HL)                  ; byte to draw
        INC     HL
        LD      A,(HL)                  ; Mask
        EX      DE,HL
        AND     (HL)                    ; video memory byte
        OR      C                       ; byte to draw
        LD      (HL),A                  ; in video memory
drawLineDelta:
        LD      HL,0
        BIT     7,H
        JR      NZ,drawLineBincr
drawLineAincr:
        LD      DE,0
        ADD     HL,DE
        LD      (drawLineDelta+1),HL
        LD      HL,drawLineX1+1
drawLineXincr:
        DB       0                      ; INC (HL) or DEC (HL)
        JR      drawLineY1
drawLineBincr:
        LD      DE,0
        ADD     HL,DE
        LD      (drawLineDelta+1),HL
        JR      drawLineY1
DrawLigneHor:
        LD      A,(IX+4)                ; x1
        LD      E,A
        LD      (fillRectBcl+1),A
        LD      A,(IX+8)                ; x2
        SUB     E
        RET     Z
        RET     C
        LD      (DrawLigneHor3+1),A     ; x2- x1
        LD      HL,(TabPen)
        LD      (DrawLigneHor1+1),HL
        LD      A,(HL)
        LD      (DrawLigneHor7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (DrawLigneHor6+1),A
        LD      L,(IX+6)                ; LineY
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
DrawLigneHor1:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
DrawLigneHor2:
        AND     A
        JR      Z,DrawLigneHor3
        RRC     C
        DEC     B
        DEC     A
        JR      DrawLigneHor2
DrawLigneHor3:
        LD      DE,0
DrawLigneHor4:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    DrawLigneHor8
        LD      A,E
DrawLigneHor5:
        INC     HL
        SUB     5
        JR      C,DrawLigneHor7
        INC     A
        LD      E,A
DrawLigneHor6:
        LD      (HL),0
        AND     A
        JR      Z,drawLineDone
        JR      DrawLigneHor5
DrawLigneHor7:
        LD      BC,&400
DrawLigneHor8:
        DEC     E
        JR      NZ,DrawLigneHor4
drawLineDone:
__endasm;
}

void fillRect(unsigned short x, unsigned short y, unsigned short width, unsigned short height) {
x;y;width;height;
__asm
        LD      A,(IX+4)
        OR      (IX+6)
        JR      NZ,fillRectInit
        LD      A,(IX+8)
        AND     (IX+10)
        CP      &FF
        JR      Z,fillFullScreen
fillRectInit:
        LD      HL,(TabPen)
        LD      (fillRectPen+1),HL
        LD      A,(HL)
        LD      (fillRect7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (fillRect5+1),A
        LD      A,(IX+4)                ; x1
        LD      (fillRectBcl+1),A
        LD      L,(IX+6)                ; y1
        LD      A,(IX+8)                ; width
        LD      (fillRect2+1),A
        LD      H,(IX+10)               ; height
fillRectBcl:
        LD      E,0                    ; rectX1
        PUSH    HL                      ; H = height, L = y1
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
fillRectPen:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
fillRect1:
        AND     A
        JR      Z,fillRect2
        RRC     C
        DEC     B
        DEC     A
        JR      fillRect1
fillRect2:
        LD      DE,0
fillRect3:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    fillRect8
        LD      A,E
fillRect4:
        INC     HL
        SUB     5
        JR      C,fillRect7
        INC     A
        LD      E,A
fillRect5:
        LD      (HL),0
        AND     A
        JR      Z,fillRect9
        JR      fillRect4
fillRect7:
        LD      BC,&400
fillRect8:
        DEC     E
        JR      NZ,fillRect3
fillRect9:
        POP     HL
        INC     L
        DEC     H
        JR      NZ,fillRectBcl
        JR     fillRectDone

fillFullScreen:
        LD      HL,(TabPen)
        LD      A,(HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR      (HL)
        LD      L,A
        LD      H,A
        DI
        LD      (fillFullScreenSP+1),SP
        LD      SP,0
        LD      B,0
fillFullScreenBcl:
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        DJNZ    fillFullScreenBcl
fillFullScreenSP:
        LD    SP,0
        EI

fillRectDone:
__endasm;
}

mr_lou

Quote from: demoniak on 15:30, 21 December 11
New start for the library  :)

Nice start!

I made a few adjustments; corrected some labels it couldn't find and such.
The drawLine method doesn't seem to be faster than the previous tests, but I don't see any exx commands in there either, so maybe you haven't used that routine yet?
(It is ok to kill the firmware routines).

The adjusted code:

void InitGfxLib() {
__asm
        LD      BC,&BC01
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg1 = 32 (256 pixels width)
        OUT     (C),C
        LD      BC,&BC02
        OUT     (C),C
        LD      BC,&BD2A                ; Center the screen horizontally
        OUT     (C),C
        LD      BC,&BC06
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg6 = 32 (256 pixels height)
        OUT     (C),C
        LD      BC,&BC07
        OUT     (C),C
        LD      BC,&BD22                ; Center the screen vertically
        OUT     (C),C
        LD      DE,&C000
        JR      InitGfxLibDone
TabPen0:
        DB      &00,&77,&00,&BB,&00,&DD,&00,&EE
        DB      &80,&77,&40,&BB,&20,&DD,&10,&EE
        DB      &08,&77,&04,&BB,&02,&DD,&01,&EE
        DB      &88,&77,&44,&BB,&22,&DD,&11,&EE
TabPen:
        DS      2
InitGfxLibDone:
__endasm;
}

void setColor(unsigned char color) {
color;
__asm
        LD      A,(IX+4)
        AND     3
        ADD     A,A
        ADD     A,A
        ADD     A,A
        LD      HL,TabPen0
        LD      B,0
        LD      C,A
        ADD     HL,BC
        LD      (TabPen),HL
__endasm;
}

void drawLine(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2) {
x1;x2;y1;y2;
__asm
        LD      A,(IX+10)
        CP      (IX+6)
        JP      Z,DrawLigneHor
        XOR     A
        LD      H,A
        LD      D,A
        LD      E,(IX+4)               ; x1
        LD      (drawLineX1+1),DE
        LD      L,(IX+6)                ; y1
        LD      (drawLineY1+1),HL
        LD      A,(IX+8)                ; x2
        LD      C,A
        LD      (drawLineX2+1),A
        LD      A,(IX+10)                ; y2
        LD      (drawLineY2+1),A
        SUB     L                       ; y2-y1
        JR      NC,drawLine2
        NEG
drawLine2:
        LD      E,A                     ; =absy
        LD      A,(drawLineX1+1)
        SUB     C                       ; x1-x2
        JR      NC,drawLineDy
        NEG
drawLineDy:
        SUB     E                       ; A = absx-absy
        LD      A,&EB                   ; &EB = EX DE,HL
        JR      C,drawLine3
        LD      A,(drawLineY2+1)
        LD      (drawLineX2+1),A
        LD      A,C
        LD      (drawLineY2+1),A        ; SWAP x2 and y2
        LD      A,(drawLineX1+1)
        LD      B,A
        LD      A,(drawLineY1+1)
        LD      (drawLineX1+1),A
        LD      A,B
        LD      (drawLineY1+1),A        ; SWAP x1 and y1
        XOR     A                       ; &00 = NOP
drawLine3:
        LD      (drawLineExchg),A
        LD      A,(drawLineY1+1)
        LD      E,A
        LD      A,(drawLineY2+1)
        SUB     E
        JR      NC,drawLine4
        LD      A,(drawLineY2+1)
        LD      (drawLineY1+1),A
        LD      A,E
        LD      (drawLineY2+1),A        ; SWAP y1 and Y2
        LD      A,(drawLineX1+1)
        LD      B,A
        LD      A,(drawLineX2+1)
        LD      (drawLineX1+1),A
        LD      A,B
        LD      (drawLineX2+1),A        ; SWAP x1 and x2
drawLine4:
        LD      A,(drawLineX1+1)
        LD      E,A
        LD      A,(drawLineX2+1)
        SUB     E
        LD      A,&35                   ; &2B = DEC (HL)
        JR      C,drawLine5
        LD      A,&34                   ; &23 = INC (HL)
drawLine5:
        LD      (drawLineXincr),A
        LD      A,(drawLineY1+1)
        LD      E,A
        LD      A,(drawLineY2+1)
        SUB     E
        LD      E,A                     ; DE = dy
drawLineX2:
        LD      HL,0
        LD      A,(drawLineX1+1)
        SUB     L                       ; x1-x2
        JR      NC,drawLine6
        NEG
drawLine6:
        LD      L,A
        ADD     HL,HL
        LD      (drawLineBincr+1),HL
        SBC     HL,DE
        LD      (drawLineDelta+1),HL
        SBC     HL,DE
        LD      (drawLineAincr+1),HL
        LD      HL,(drawLineY1+1)
        DEC     HL
        LD      (drawLineY1+1),HL
        LD      HL,(TabPen)
        LD      (drawLinePen+1),HL
drawLineY1:
        LD      HL,0
        INC     HL
        LD      (drawLineY1+1),HL
        EX      DE,HL                   ; DE = y1
drawLineY2:
        LD      HL,0
        SBC     HL,DE                   ; HL = y2 - y1
        JP      C,drawLineDone
drawLineX1:
        LD      HL,0                    ; HL = x1
drawLineExchg:
        DB      0                       ; NOP or EX DE,HL
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        ADD     A,A
        AND     C
        LD      D,A                     ; D = NumPixel * 2
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      L,H
        LD      H,0
drawLinePen:
        LD      BC,0
        ADD     HL,BC
        LD      C,(HL)                  ; byte to draw
        INC     HL
        LD      A,(HL)                  ; Mask
        EX      DE,HL
        AND     (HL)                    ; video memory byte
        OR      C                       ; byte to draw
        LD      (HL),A                  ; in video memory
drawLineDelta:
        LD      HL,0
        BIT     7,H
        JR      NZ,drawLineBincr
drawLineAincr:
        LD      DE,0
        ADD     HL,DE
        LD      (drawLineDelta+1),HL
        LD      HL,drawLineX1+1
drawLineXincr:
        DB       0                      ; INC (HL) or DEC (HL)
        JR      drawLineY1
drawLineBincr:
        LD      DE,0
        ADD     HL,DE
        LD      (drawLineDelta+1),HL
        JR      drawLineY1
DrawLigneHor:
        LD      A,(IX+4)                ; x1
        LD      E,A
        LD      (fillRectBcl+1),A
        LD      A,(IX+8)                ; x2
        SUB     E
        RET     Z
        RET     C
        LD      (DrawLigneHor3+1),A     ; x2- x1
        LD      HL,(TabPen)
        LD      (DrawLigneHor1+1),HL
        LD      A,(HL)
        LD      (DrawLigneHor7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (DrawLigneHor6+1),A
        LD      L,(IX+6)                ; LineY
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
DrawLigneHor1:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
DrawLigneHor2:
        AND     A
        JR      Z,DrawLigneHor3
        RRC     C
        DEC     B
        DEC     A
        JR      DrawLigneHor2
DrawLigneHor3:
        LD      DE,0
DrawLigneHor4:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    DrawLigneHor8
        LD      A,E
DrawLigneHor5:
        INC     HL
        SUB     5
        JR      C,DrawLigneHor7
        INC     A
        LD      E,A
DrawLigneHor6:
        LD      (HL),0
        AND     A
        JR      Z,drawLineDone
        JR      DrawLigneHor5
DrawLigneHor7:
        LD      BC,&400
DrawLigneHor8:
        DEC     E
        JR      NZ,DrawLigneHor4
drawLineDone:
__endasm;
}

void fillRect(unsigned short x, unsigned short y, unsigned short width, unsigned short height) {
x;y;width;height;
__asm
        LD      A,(IX+4)
        OR      (IX+6)
        JR      NZ,fillRectInit
        LD      A,(IX+8)
        AND     (IX+10)
        CP      &FF
        JR      Z,fillFullScreen
fillRectInit:
        LD      HL,(TabPen)
        LD      (fillRectPen+1),HL
        LD      A,(HL)
        LD      (fillRect7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (fillRect5+1),A
        LD      A,(IX+4)                ; x1
        LD      (fillRectBcl+1),A
        LD      L,(IX+6)                ; y1
        LD      A,(IX+8)                ; width
        LD      (fillRect2+1),A
        LD      H,(IX+10)               ; height
fillRectBcl:
        LD      E,0                    ; rectX1
        PUSH    HL                      ; H = height, L = y1
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
fillRectPen:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
fillRect1:
        AND     A
        JR      Z,fillRect2
        RRC     C
        DEC     B
        DEC     A
        JR      fillRect1
fillRect2:
        LD      DE,0
fillRect3:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    fillRect8
        LD      A,E
fillRect4:
        INC     HL
        SUB     5
        JR      C,fillRect7
        INC     A
        LD      E,A
fillRect5:
        LD      (HL),0
        AND     A
        JR      Z,fillRect9
        JR      fillRect4
fillRect7:
        LD      BC,&400
fillRect8:
        DEC     E
        JR      NZ,fillRect3
fillRect9:
        POP     HL
        INC     L
        DEC     H
        JR      NZ,fillRectBcl
        JR     fillRectDone

fillFullScreen:
        LD      HL,(TabPen)
        LD      A,(HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR      (HL)
        LD      L,A
        LD      H,A
        DI
        LD      (fillFullScreenSP+1),SP
        LD      SP,0
        LD      B,0
fillFullScreenBcl:
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        DJNZ    fillFullScreenBcl
fillFullScreenSP:
        LD    SP,0
        EI

fillRectDone:
__endasm;
}

mr_lou

Hm, I see now I probably shouldn't have locked the "Help with SDCC" thread, since I now need....help with SDCC.

I'm trying to implement pointers to functions, and have been looking at these two links:
Function pointers in C
SDCC manual about pointers to specific memory spaces

My test is very simple, and taken straight from the first link (only deleting the stdio.h and printf):

void my_int_func(int x)
{
    // Do nothing
}


int main()
{
    void (*foo)(int);
    foo = &my_int_func;

    /* call my_int_func (note that you do not need to write (*foo)(2) ) */
    foo( 2 );
    /* but if you want to, you may */
    (*foo)( 2 );

    return 0;
}


That gives me the following error;

ERROR on line 55 of file main_maxam.asm
ERROR: Symbol '__sdcc_call_hl' is undefined

File main_maxam.asm: (line 55 is marked with an arrow)

;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 3.1.1 7107 (Dec 15 2011) (Linux)
; This file was generated Thu Dec 22 08:40:14 2011
;--------------------------------------------------------
     
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
;--------------------------------------------------------
;  ram data
;--------------------------------------------------------
;--------------------------------------------------------
; overlayable items in  ram
;--------------------------------------------------------
;--------------------------------------------------------
; external initialized ram data
;--------------------------------------------------------
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
;--------------------------------------------------------
; Home
;--------------------------------------------------------
;--------------------------------------------------------
; code
;--------------------------------------------------------
;main.c:1: void my_int_func(int x)
;    ---------------------------------
; Function my_int_func
; ---------------------------------
_my_int_func_start:
_my_int_func:
    push    ix
;main.c:4: }
    pop    ix
    ret
_my_int_func_end:
;main.c:7: int main()
;    ---------------------------------
; Function main
; ---------------------------------
_main_start:
_main:
;main.c:10: foo = &my_int_func;
    ld    de,_my_int_func
;main.c:13: foo( 2 );
    push    de
    ld    hl, &0002
    push    hl
    ex    de,hl
    call    __sdcc_call_hl    <--- that is line 55
    pop    af
    pop    de
;main.c:15: (*foo)( 2 );
    ld    hl, &0002
    push    hl
    ex    de,hl
    call    __sdcc_call_hl
    pop    af
;main.c:17: return 0;
    ld    hl, &0000
    ret
_main_end:


Can anyone help? Maybe pointers to functions aren't possible in SDCC?

mr_lou

#7
Ok, I have spent a long time thinking about a solution for the double-buffering, and have come up with this.
Would very much like to hear if you find this completely crazy, or something that could work.

First, let's take a look at a pseudo-code implementation of Image.getRGB() and Graphics.drawRGB()

Image.getRGB(int[] data, int offset, int scanlength, int x, int y, int width, int height) {
// Remember, we're ignoring offset and scanlength for now
int pos = 0;
for (getY=y;getY<y+height;getY++) {
  for (getX=x;getX<x+width;getX++) {
  data[pos] = screenByteAt(getX,getY);
  pos++;
  }
}
}

Graphics.drawRGB(int[] data, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha) {
// Remember, we're ignoring offset and scanlength for now
int pos = 0;
for (setY=y;setY<y+height;setY++) {
  for (setX=x;setX<x+width/4;setX++) { // We divide by 4 because each byte contains 4 pixels
  plotByte(setX, setY, data[pos]);
  pos++;
  }
}
}


Simple stuff.

Using these functions in J2ME, we will do this:
int[] data = new int[width*height];
So if we want to grab a 16x16 pixels area, we'll define the array size to be 256
int[] data = new int[256];

Using these functions in sMIDP2lib, a coder will probably also do this:
int data[256];
The thing is, we actually only need 64 bytes to store a 16x16 pixel area on the CPC in MODE 1,
because 1 byte represents 4 pixels, (which in theory means we could settle for an int array size of 32....)
So the alert coder who knows a bit about the CPC will divide the value with 4. Other coders won't, and will thus waste memory.
Anyway. For my idea about a double-buffer solution, we will divide by 4 and plus 5. So:
int data[69];

When calling getRGB, we will store the 16x16 pixels in the array data.
First we will ask sMIDP2lib which of the two buffer screens currently is the one we are drawing too. (Meaning, the one that is currently NOT visible).
If we are currently drawing to buffer-screen 0, then we will store the byte data in the least significant byte of the int array.
If we are currently drawing to buffer-screen 1, then we will store the byte data in the most significant byte of the int array.
Let's pretend we're currently drawing on buffer-screen 0, so we will save the 64 bytes in the least significant byte of the int array.
This will occupy the first 64 16bit spaces of the array, leaving 5 16bit spaces untouched.
Of these untouched 5 remaining spaces, we will use 1 to store which buffer-screen stored data last, and 2 more to store the x and y values it was taken from if the buffer-screen was 0, and 2 more to store the x and y values in was taken from if the buffer-screen was 1.

So now we have an int array containing all the image-data in either the least significant byte or the most significant byte.

Then we call flushGraphics(), which means the buffer-screens toggles. Now we're drawing on screen-buffer 1 (while screen-buffer 0 is visible).

If we now call getRGB again using the same array, the data we saved previously will not be overwritten. Because now we will use the other bytes to store the image-data.


When we then call drawRGB(data, 0, 0, 0, 0, 16, 16, true), the first thing this function does, is to check which buffer-screen is currently the one we're drawing too. We will NEVER draw to the current visible screen when double-buffering is active.

If we are currently drawing to buffer-screen 0, we KNOW that we will be using the data in the least significant byte.
If we are currently drawing to buffer-screen 1, we KNOW that we will be using the data in the most significant byte.

The only question to ask is this: Which coordinates should be used? This is decided this way:

If we are currently drawing to buffer-screen 0, and the buffer-screen that was used last time data was written to the array is also buffer-screen 0, then the data will be drawn at the coordinates in the parameters of the function.

If we are currently drawing to buffer-screen 0, but the buffer-screen that was used last time data was written to the array is buffer-screen 1, then the data will be drawn at the coordinates stored in the end of the data array. (The x and y values for buffer-screen 0).

This covers the 2 scenarios where getRGB and drawRGB will typically be used:
Scenario 1: Copy a piece of the screen in order to draw it elsewhere on the screen in the same frame.
Scenario 2: Copy a piece of the screen in order to cover up some sprite in the next frame.

The buffer-screen number stored in the end of the data array will reveal which scenario the coder is using, and we can thus give him the expected result.

With these things in mind, let's take a look at the two functions again, with the added functionality.


Image.getRGB(int[] data, int offset, int scanlength, int x, int y, int width, int height) {
// Remember, we're ignoring offset and scanlength for now
int pos = 0;
for (getY=y;getY<y+height;getY++) {
  for (getX=x;getX<x+width;getX++) {
  if (getCurrentScreenBuffer()==0) data[pos] |= screenByteAt(getX,getY);
  else data[pos] |= (screenByteAt(getX,getY)<<8);
  pos++;
  }
}
data[pos] = getCurrentBufferScreen(); // Returns 0 or 1
if (data[pos]==0) {
  data[pos+1]=x;
  data[pos+2]=y;
} else {
  data[pos+3]=x;
  data[pos+4]=y;
}
}

Graphics.drawRGB(int[] data, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha) {
// Remember, we're ignoring offset and scanlength for now
int pos = data[(width*height)/4+1]; // We know that image-data is stored using 1/4 the space as width*height
int bufferscreen = data[pos]; // So the buffer-screen number and x,y coordinates are located after that
if (getCurrentBufferScreen()!=buffer-screen) { // If we're currently drawing to a different buffer-screen than the data was taken from
  if (bufferscreen==0) { // Then we must use the coordinates where the data was taken from too.
   x = data[pos+1];             // In other words, sMIDP2lib must set the address-offset of bufferscreen 0 here
   y = data[pos+2]; 
  } else {
   x = data[pos+3];             // Or bufferscreen 1
   y = data[pos+4];
  }                                             // Otherwise address-offset must be the address of the coordinates from the parameters in the current bufferscreen.
}
pos = 0;
for (setY=y;setY<y+height;setY++) {
  for (setX=x;setX<x+width/4;setX++) {
  if (getCurrentBufferScreen()==0) plotByte(setX, setY, (data[pos]&ff));
  else plotByte(setX, setY, (data[pos]>>8));
  pos++;
  }
}
}


As far as I can see, this will solve the problematic-to-"un-draw" issue when using getRGB and drawRGB.
I haven't looked into stuff like drawLine and drawImage yet though.
What have I missed? (There must be something. Can you spot what it is?)

EDIT: Have corrected some things in the code and description.
EDIT2: Noticed that some code was missing, most likely due to smiley-looking-code: the number 8 followed by )

mr_lou

Quote from: mr_lou on 08:46, 22 December 11I'm trying to implement pointers to functions, and have been looking at these two links:
Function pointers in C
SDCC manual about pointers to specific memory spaces

...

That gives me the following error;

ERROR on line 55 of file main_maxam.asm
ERROR: Symbol '__sdcc_call_hl' is undefined

To answer my own question here, it looks like pasmo just can't compile the assembler code generate by SDCC.
If I use SDCC to compile the C source directly to a binary, then function pointers work fine.

So that's good news and bad news...
The good news is that it's still possible to do this. The bad news is, that all assembler code has to be in ASxxxx syntax.
Demoniak has written some great routines in Maxam syntax already, so I have to look into translating those into ASxxxx syntax.
I don't suppose anyone here knows what some of the differences are between Maxam syntax and ASxxxx syntax? A short list of different ways of writing commands would be very handy.

mr_lou

Quote from: mr_lou on 09:33, 26 December 11The good news is that it's still possible to do this. The bad news is, that all assembler code has to be in ASxxxx syntax.
Demoniak has written some great routines in Maxam syntax already, so I have to look into translating those into ASxxxx syntax.
I don't suppose anyone here knows what some of the differences are between Maxam syntax and ASxxxx syntax? A short list of different ways of writing commands would be very handy.

I've found this: http://wikiti.brandonw.net/index.php?title=Programming_under_Unix-like_operating_systems
It says this about ASxxxx:

QuoteNote that the syntax is rather different from that of most Z80 assemblers.  The important differences are

       
  • Immediate values are marked with #.
  • Indexed memory access is written as N(ix) rather than (ix+N).
  • Constants are written differently: 0xAA, 0hAA, or $$AA for hexadecimal; 0o252, 0q252, or $&252 for octal; 0b10101010 or $%10101010 for binary.
There is also a modified version of ASxxxx distributed with the Small Device C Compiler.  This version is, if anything, more confusing to use due to the poorly-documented changes made by the SDCC team.

That doesn't sound too good.

So currently, I think the whole project depends on whether or not any CPC assembler coder is willing to write ASxxxx syntax routines for the various methods. I doubt that, but let's see.

mr_lou

Have been mailing a bit with Arnaud aka NoRecess today.

He gives an example of function pointers that does work with SDCC and SDCC2Pasmo:

// ----------------------------------------------------------------------------
typedef struct MyStruct {
void (*TestFunction)(int);
};

// ----------------------------------------------------------------------------
void test(int a)
{
}

// ----------------------------------------------------------------------------
void MainFunction()
{
struct MyStruct *myStruct;
myStruct = (struct MyStruct *)0xC000; // any good mem location..
myStruct->TestFunction = test;
myStruct->TestFunction(14); // call your function
}


We cannot use that procedure for sMIDP2lib though, since it'll break the language architecture of all the other platforms + we want to avoid setting specific memory addresses. In other words, doing it like that prevents us from being able to just copy the code more or less directly from our CPC project into our J2ME project.
Instead, we need to be able to write it like this:


// ----------------------------------------------------------------------------
typedef struct MyStruct {
void (*TestFunction)(int);
} MyStruct;

// ----------------------------------------------------------------------------
void test(int a)
{
}

MyStruct s;

void init() {
s.TestFunction = &test;
}

// ----------------------------------------------------------------------------
void main() {
init();
s.TestFunction(14);
}


- and that is indeed possible if we stick with SDCC without SDCC2Pasmo. Sadly that means we're stuck with ASxxxx syntax assembler though.


Also, I'd like to point out that this project is first and foremost just an experiment: To see if it can be done to implement a library that thus makes it easier to port your creations to other platforms. It should be considered as a cozy one-step-at-a-time build-up-slowly-over-12-months-or-so brain-teaser for everyone feeling like participating.
If it proves to be possible, I eventually expect to make a small game, for Amstrad CPC + J2ME, (possibly also HTML5 and Android) as a demonstration, with public source so others can try the same. But that's a long time into the future from now.  ;)

It should also be pointed out that sMIDP2lib is not a game-library. It is merely a graphics library that gives you some of the same methods MIDP2.0 gives you, meaning when/if you've coded whatever for the CPC, it should theoretically be a small task porting it to J2ME (and any other platform where sMIDP2lib exists in some form).
I don't expect it to be ultra fast on the CPC. It might not even be adequate, but we won't know till we try.

Arnaud suggested it would be a better idea to make a library that was more optimized for the CPC.
This could also be a project to startup of course, and then make similar libraries for other platforms, allowing easier porting. It makes sense to build the lib that benefits the weakest platform (which is exactly why those libs I've made for HTML5, Flash and Android is based on MIDP2 so that it runs fastest on J2ME devices, which are usually slower than the other platforms).

Seems to me though, that if we'd rather go in that direction, we might as well take an existing library, like CPCrslib, and port that to other platforms.

For now, I expect to keep looking at sMIDP2lib as long as anyone (currently only Demoniak) feels like helping out. Any feedback is most welcome. If you like the idea of sMIDP2lib, please let me know.

Optimus

Hey, what a coincidence. Yesterday I had the same exact problem with using function pointers. I don't usually need function pointers, it was just a test to see if one can call firmware routines from pure C code without the use of assembly. But the problem only occured when I updated the SDCC version to 3.1.0.


Interesting project there you have. Although I have almost never coded java for mobile phones, I'd love to see how well this performs on CPC.

mr_lou

Quote from: Optimus on 13:21, 28 December 11Interesting project there you have. Although I have almost never coded java for mobile phones, I'd love to see how well this performs on CPC.

Yea, that is one of the most interesting things. Performance has to be acceptable.
But if it is, I think this library could result in more CPC productions. I think a lot of people out there would like to develop something for the CPC, but never does because there's no time. But if the code is reusable on other platforms, then they might support the CPC. At least that's the idea.

It doesn't have to be based on the MIDP2 API though. I'm just doing that because a lot of the work is already done then, since I've been looking into sMIDP2lib's for HTML5 and Android and Flash already. (See links at the bottom of the project-page for live demonstrations of HTML5 and Flash examples).


Anyway, I have a question (to everyone) about switching screens on the CPC: Will it switch screen equally fast no matter how much graphics is on the screen?
For example. Let's say we have two screens, and one of them is blank, and the other is full of graphics. Nothing is being drawn. Only screen-toggling is going on. Will be then be slower to switch to the screen that's full of graphics or will it be equally speed as when toggling to the blank one?

demoniak

#13
Quote from: mr_lou on 13:41, 28 December 11
Anyway, I have a question (to everyone) about switching screens on the CPC: Will it switch screen equally fast no matter how much graphics is on the screen?
For example. Let's say we have two screens, and one of them is blank, and the other is full of graphics. Nothing is being drawn. Only screen-toggling is going on. Will be then be slower to switch to the screen that's full of graphics or will it be equally speed as when toggling to the blank one?

No matter what on sreen, swithing from a screen to another by setting the register 12 of the CRTC (double buffer technique) take only some microseconds.
And you can test this in basic :

Switching to buffered screen:OUT &BC00,12:out &BD00,16

Switching to "normal" screen:OUT &BC00,12:out &BD00,48

mr_lou

That's great.

I have an idea for double-buffering I think might work. It's probably a bit geeky though.

Our screen is 256x256 pixels, which I calculate to 16384 bytes. We'll need two of those, so we've already used 32768 bytes.

arnoldemu suggested the "backscreen"-buffer to always be the one we draw to, and it's always invisible. Then afterwards we throw it to the front-screen. In other words, no toggling is going on. In addition to the two screens some extra dirty-buffer should be used to keep track of which parts of the screen has been drawn to, so that only those parts are updated on the front-screen.
The dirty-buffer could be a simply 8x8 pixel tile system, meaning it would take about 256 bytes or so.

I have an idea that's roughly based on that idea.
We have the two screens. While one is visible we draw to the other, and then we toggle screens.
And here comes my somewhat odd suggestion.
We create what I'm calling a "function buffer". This buffer stores the commands in binary code previously called on the previous screen.
Example.
We're drawing to screen 0, by calling g.drawLine(0,0,100,100);
the drawLine() method draws a line, and then it adds its own binary code to the function buffer.
We then call flushGraphics(). This will make the screens toggle, and then the code stored in the function buffer will be called before we start the next loop.

Is this making any sense to anyone?

The function buffer will be keeping track of what was drawn in screen 0, and then draw those exact things in screen 1 too.

So if we have e.g.

void drawLine(int x, int y, int width, int height) - that will create a label is assembler called _drawLine
The C function pulls the parameters from the stack.
So what will be stored in the function buffer is this the binary code for: push x,y,width,height and call _drawLine
The last command of the function buffer, after all commands, must always be RET, so that the very first thing flushGraphics() can do is call _functionBuffer
So the function buffer will always contain runnable code that has been dynamically created in each loop.

What do you think? Silly?

Axelay


Would it not be possible to have two 'dirty buffers', one for each physical screen?  Rather than use the buffer to identify what needs copying to the visible screen, it would be used to identify what needs restoring or clearing for that screen in two frames time.  So the sequence would be write to the hidden screen, fill it's dirty buffer, show the hidden screen with the hardware swap.  Use the second dirty buffer of the newly hidden screen to restore that screen to background, write the moving objects to it, fill that screens dirty buffer, then swap screens with the hardware again.  Now use the original dirty buffer to restore the originally hidden screen to background only, and repeat the sequence.

demoniak

#16
Here is the last drawLine routine :

void initGfxLib() {
__asm
        LD      BC,&BC01
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg1 = 32 (256 pixels width)
        OUT  (C),C
        LD      BC,&BC02
        OUT     (C),C
        LD      BC,&BD2A                ; Center the screen horizontally
        OUT     (C),C
        LD      BC,&BC06
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg6 = 32 (256 pixels height)
        OUT     (C),C
        LD      BC,&BC07
        OUT     (C),C
        LD      BC,&BD22                ; Center the screen vertically
        OUT     (C),C
__endasm;
}

void setColor(unsigned char color) {
color;
__asm
        LD      A,(IX+4)
        AND     3
        ADD     A,A
        ADD     A,A
        ADD     A,A
        LD      H,TabPen0/256
        LD      L,A
        LD      (TabPen),HL
__endasm;
}

void drawLine(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2) {
x1;x2;y1;y2;
;
; B = X1
; C = Y1
; D = X2
; E = Y2
;__asm
        LD      A,(IX+10)               ; y2
        LD      C,(IX+6)                ; y1
        CP      C
        JR      Z,drawLineHor
        LD      B,(IX+4)                ; x1
        LD      D,(IX+8)                ; x2
        LD      E,A                     ; y2
        LD      HL,(TabPen)
        LD      (drawLineCoul+1),HL
        LD      A,E
        SUB     C
        JR      NC,drawLineTst1
        NEG
drawLineTst1:
        LD      H,A                     ; H = Abs(Y2-Y1)
        LD      A,D
        SUB     B
        JR      NC,drawLineTst2
        NEG
drawLineTst2:
        CP      H                       ; A=Abs(X2-X1) CP Abs(Y2-Y1)
        JR      C,drawLineV             ; Si A>=H -> Ligne par l'axe horizontal
        LD      A,B
        LD      B,C
        LD      C,A                     ; Inversion X1 et Y1
        LD      A,D
        LD      D,E
        LD      E,A                     ; Inversion X2 et Y2
        LD      A,&68                   ; LD L,B
        LD      (drawLineOrd1),A
        LD      A,&79                   ; LD A,C
        JR      drawLine1
drawLineV:
        LD      A,&69                   ; LD L,C
        LD      (drawLineOrd1),A
        LD      A,&78                   ; LD A,B
drawLine1:
        LD      (drawLineAbs1),A
        LD      (drawLineAbs2),A
        LD      A,E
        CP      C
        JR      NC,drawLine2
        LD      E,C
        LD      C,A                     ; Echange Y1 et Y2
        LD      A,D
        lD      D,B
        LD      B,A                     ; Echange X1 et X2
drawLine2:
        LD      A,D
        SUB     B
        LD      L,&04                   ; INC B
        JR      NC,drawLine3
        NEG
        INC     L                       ; DEC B
drawLine3:
        EX      AF,AF'                  ; Stockage DX
        LD      A,L
        LD      (drawLineXincr),A       ; Stockage INC ou DEC B
        LD      A,C
        SUB     E
        EXX
        LD      E,A                     ; Stockage -DY
        LD      D,&FF
        EX      AF,AF'                  ; Récupère DX
        LD      L,A                     ; L = DX
        LD      H,&00
        ADD     HL,HL                   ; DX * 2
        LD      B,H
        LD      C,L                     ; Bincr = DX * 2 (BC)
        ADD     HL,DE                   ; - DY
        ADD     HL,DE                   ; - DY
        EX      DE,HL                   ; Aincr = DX * 2 - DY * 2 (DE)
        ADD     HL,BC                   ; delta = DX * 2 - DY
        EXX
        LD      A,E                     ; Récupère Y2
        ;
        ; faire un point aux coordonnées X(Reg.B), Y(Reg.C) OU Y,X
        ;
drawLineBcl:
        EX      AF,AF'                  ; Sauvegarde Y2
        LD      H,TabAdrEcr/256
drawLineOrd1:
        LD      L,C                     ; y to plot
drawLineAbs1:
        LD      A,B
        AND     A
        RRA
        AND     A
        RRA                             ; x/4
        ADD     A,(HL)
        LD      E,A
        INC     H                       ; Adresse des poids forts
        LD      A,(HL)
drawLineOffsetVideo:
        ADC     A,&C0
        LD      D,A                     ; Reg.DE = adresse mémoire écran (0,y)
drawLineAbs2:
        LD      A,B
        AND     3
        RLA
drawLineCoul:
        LD      HL,0
        ADD     A,L
        LD      L,A
        LD      A,(DE)                  ; Octet mémoire écran
        AND     (HL)                    ; Masque
        INC     L
        OR      (HL)                    ; Octet à écrire en mémoire écran
        LD      (DE),A
        EX      AF,AF'                  ; Récupère Y2
        INC     C                       ; Incrémenter Y1
        EXX
        BIT     7,H                     ; Delta négatif ?
        JR      Z,drawLineAincr
drawLineBincr:
        ADD     HL,BC                   ; Delta += Bincr
        EXX
        CP      C                       ; compare Y2 à Y1
        JR      NZ,drawLineBcl
        JR      drawLineDone
drawLineAincr:
        ADD     HL,DE                   ; Delta += Aincr
        EXX
drawLineXincr:
        INC     B                       ; ou dec b
        CP      C                       ; compare Y2-Y1
        JR      NZ,drawLineBcl
        JR      drawLineDone

drawLineHor:
        LD      A,(IX+4)                ; x1
        LD      E,A
        LD      A,(IX+8)                ; x2
        SUB     E
        RET     Z
        RET     C
        LD      (DrawLigneHor3+1),A     ; x2- x1
        LD      HL,(TabPen)
        LD      (DrawLigneHor1+1),HL
        LD      A,(HL)
        LD      (DrawLigneHor7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (DrawLigneHor6+1),A
        LD      L,(IX+6)                ; LineY
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
DrawLigneHor1:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
DrawLigneHor2:
        AND     A
        JR      Z,DrawLigneHor3
        RRC     C
        DEC     B
        DEC     A
        JR      DrawLigneHor2
DrawLigneHor3:
        LD      DE,0
DrawLigneHor4:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    DrawLigneHor8
        LD      A,E
DrawLigneHor5:
        INC     HL
        SUB     5
        JR      C,DrawLigneHor7
        INC     A
        LD      E,A
DrawLigneHor6:
        LD      (HL),0
        AND     A
        JR      Z,DrawLigneDone
        JR      DrawLigneHor5
DrawLigneHor7:
        LD      BC,&400
DrawLigneHor8:
        DEC     E
        JR      NZ,DrawLigneHor4
drawLineDone:
__endasm;
}

void fillRect(unsigned short x1, unsigned short y1, unsigned short width, unsigned short height) {
x1;x2;width;height;
__asm
        LD      A,(IX+4)
        OR      (IX+6)
        JR      NZ,fillRectInit
        LD      A,(IX+8)
        AND     (IX+10)
        CP      &FF
        JR      Z,fillFullScreen
fillRectInit:
        LD      HL,(TabPen)
        LD      (fillRectPen+1),HL
        INC     HL
        LD      A,(HL)
        LD      (fillRect7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (fillRect5+1),A
        LD      A,(IX+4)                ; x1
        LD      (fillRectBcl+1),A
        LD      L,(IX+6)                ; y1
        LD      A,(IX+8)                ; width
        LD      (fillRect2+1),A
        LD      H,(IX+10)               ; height
fillRectBcl:
        LD      E,0                     ; rectX1
        PUSH    HL                      ; H = height, L = y1
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
fillRectPen:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
fillRect1:
        AND     A
        JR      Z,fillRect2
        RRC     C
        DEC     B
        DEC     A
        JR      fillRect1
fillRect2:
        LD      DE,0
fillRect3:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    fillRect8
        LD      A,E
fillRect4:
        INC     HL
        SUB     5
        JR      C,fillRect7
        INC     A
        LD      E,A
fillRect5:
        LD      (HL),0
        AND     A
        JR      Z,fillRect9
        JR      fillRect4
fillRect7:
        LD      BC,&400
fillRect8:
        DEC     E
        JR      NZ,fillRect3
fillRect9:
        POP     HL
        INC     L
        DEC     H
        JR      NZ,fillRectBcl
        JR     fillRectDone

fillFullScreen:
        LD      HL,(TabPen)
        INC     HL
        LD      A,(HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR      (HL)
        LD      L,A
        LD      H,A
        LD      (fillFullScreenSP+1),SP
        LD      SP,0
        LD      B,0
fillFullScreenBcl:
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        DJNZ    fillFullScreenBcl
fillFullScreenSP:
        LD    SP,0

fillRectDone:
__endasm;
}

/* This part must be aligned on a 256 byte address
__asm
TabAdrEcr:
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0800, &1810, &2820, &3830, &0800, &1810, &2820, &3830
        DW      &0800, &1810, &2820, &3830, &0800, &1810, &2820, &3830
        DW      &0901, &1911, &2921, &3931, &0901, &1911, &2921, &3931
        DW      &0901, &1911, &2921, &3931, &0901, &1911, &2921, &3931
        DW      &0A02, &1A12, &2A22, &3A32, &0A02, &1A12, &2A22, &3A32
        DW      &0A02, &1A12, &2A22, &3A32, &0A02, &1A12, &2A22, &3A32
        DW      &0B03, &1B13, &2B23, &3B33, &0B03, &1B13, &2B23, &3B33
        DW      &0B03, &1B13, &2B23, &3B33, &0B03, &1B13, &2B23, &3B33
        DW      &0C04, &1C14, &2C24, &3C34, &0C04, &1C14, &2C24, &3C34
        DW      &0C04, &1C14, &2C24, &3C34, &0C04, &1C14, &2C24, &3C34
        DW      &0D05, &1D15, &2D25, &3D35, &0D05, &1D15, &2D25, &3D35
        DW      &0D05, &1D15, &2D25, &3D35, &0D05, &1D15, &2D25, &3D35
        DW      &0E06, &1E16, &2E26, &3E36, &0E06, &1E16, &2E26, &3E36
        DW      &0E06, &1E16, &2E26, &3E36, &0E06, &1E16, &2E26, &3E36
        DW      &0F07, &1F17, &2F27, &3F37, &0F07, &1F17, &2F27, &3F37
        DW      &0F07, &1F17, &2F27, &3F37, &0F07, &1F17, &2F27, &3F37

TabPen0:
        DB      &77, &00, &BB, &00, &DD, &00, &EE, &00
        DB      &77, &80, &BB, &40, &DD, &20, &EE, &10
        DB      &77, &08, &BB, &04, &DD, &02, &EE, &01
        DB      &77, &88, &BB, &44, &DD, &22, &EE, &11
__endasm;
*/

mr_lou

Hey Axelay, thanks for replying.

Quote from: Axelay on 03:41, 29 December 11Rather than use the buffer to identify what needs copying to the visible screen, it would be used to identify what needs restoring or clearing for that screen in two frames time.

The thing is, we don't know what needs restoring or clearing in two frames time. We don't know if the coder is moving a sprite, or if he's drawing multiple copies of the sprite. The C coder has to be able to code as if it was J2ME. The fact that there are two buffer-screens is transparent to him.

That's why I think the only solution is to
10 Draw to hidden screen + fill function buffer with binary code to call the same draw routine in next frame
20 Toggle screens to show the screen that was just drawn to + update the now invisible screen to contain the same content as the visible screen
30 GOTO 10

First thought is something like this: . o O ( Hmm, wouldn't that be rather slow? )
But then I think, that those other buffer-solutions should also be somewhat slow, so maybe the difference isn't that big?

If we're calling drawLine(x,y,width,height) for example, SDCC first puts the 4 parameters onto the stack, and then calls the routine.
Writing the above program again, with more details would look like this:
10 Draw to hidden screen: drawLine(7, 7, 10, 10);
11 Write to function buffer: DD E5 07 DD E5 07 DD E5 0A DD E5 0A CD (_drawLine)
(As far as I could see DD E5 = opcode for PUSH IX)
12 Draw more stuff and put into function buffer. When done drawing, append to function buffer: C9 (to return from the call)
20 Toggle screen
21 Call _functionBuffer to perform the same drawing routines we did on the previous screen
30 GOTO 10

Next thought: . o O ( Hmm, function buffer will probably need to be 4k big.... Takes 15 bytes just to draw a line... )

So if you're drawing e.g. 256 lines or sprites, then function buffer will need 4096 bytes, which does seem quite a lot. On the other hand, you'll rarely draw 256 sprites.... but because you probably needs to draw 256 sprites at startup (e.g. to draw the level), then function buffer will need 4k.

I should probably mention again though, that memory usage isn't a big problem, since the coder is supposed to dynamically load whatever resources he needs. E.g. don't load the graphics for level 2 yet if the player is still playing level 1.

Anyway, what do you think about this idea to use a function buffer like this? Genius solution or completely silly idea?

mr_lou

Quote from: demoniak on 08:51, 29 December 11Here is the last drawLine routine

Brilliant! Thanks a lot. I'll look into it, and see how I can make those TabAdrEcr align with 256 somehow.

mr_lou

#19
@Demoniak, I'm fiddling with the new code, and getting an error:

ERROR: Symbol 'TabPen' is undefined

I see that you have a label called TabPen0, but not one called TabPen. Yet TabPen is referred to multiple places.
Am I getting that error because I haven't aligned that TabAdrEcr label yet, or should TabPen be replaced with TabPen0?


EDIT: Nevermind. I looked at the old version, and saw a TabPen: DS 2 which I just inserted, and then it seems to work. Now I'll look into how to align it.

mr_lou

Alright.

I aligned the TabAdrEcr by adjusting the start-address, and inserting a JUMP. Probably needs to be done a better way later. For now it's sufficient.
Also had to correct some other minor issues, like relative jumps out of reach, and labels mismatches.

Two comparisons again. SDCC.BIN:

#include "sMIDP2lib.h"

void main(void) {
int p,x,y;
initGfxLib();

while (1) {
setColor(0);
fillRect(0,0,255,255);

p=1;
for (x=0;x<255;x+=5) {
setColor(p);
drawLine(x,0,x,255);
p++; if (p>3) p=1;
}
for (y=0;y<255;y+=5) {
setColor(p);
drawLine(0,y,255,y);
p++; if (p>3) p=1;
}
}
}


BASIC.BAS:

10 MODE 1
15 P=1
20 FOR X%=0 TO 640 STEP 10:ORIGIN X%,0:DRAW 0,400,P:P=P+1:IF P=4 THEN P=1
30 NEXT
40 FOR Y%=0 TO 400 STEP 10:ORIGION 0,Y%:DRAW 640,0,P:P=P+1:IF P=4 THEN P=1
50 NEXT
60 GOTO 10


I know the two sources aren't exactly identical, but still...

sMIDP2lib.h as it currently looks after my adjustments.

void initGfxLib() {
__asm
                JP InitGfxLib
               
TabAdrEcr:
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0000, &0000, &0000, &0000, &4040, &4040, &4040, &4040
        DW      &8080, &8080, &8080, &8080, &C0C0, &C0C0, &C0C0, &C0C0
        DW      &0800, &1810, &2820, &3830, &0800, &1810, &2820, &3830
        DW      &0800, &1810, &2820, &3830, &0800, &1810, &2820, &3830
        DW      &0901, &1911, &2921, &3931, &0901, &1911, &2921, &3931
        DW      &0901, &1911, &2921, &3931, &0901, &1911, &2921, &3931
        DW      &0A02, &1A12, &2A22, &3A32, &0A02, &1A12, &2A22, &3A32
        DW      &0A02, &1A12, &2A22, &3A32, &0A02, &1A12, &2A22, &3A32
        DW      &0B03, &1B13, &2B23, &3B33, &0B03, &1B13, &2B23, &3B33
        DW      &0B03, &1B13, &2B23, &3B33, &0B03, &1B13, &2B23, &3B33
        DW      &0C04, &1C14, &2C24, &3C34, &0C04, &1C14, &2C24, &3C34
        DW      &0C04, &1C14, &2C24, &3C34, &0C04, &1C14, &2C24, &3C34
        DW      &0D05, &1D15, &2D25, &3D35, &0D05, &1D15, &2D25, &3D35
        DW      &0D05, &1D15, &2D25, &3D35, &0D05, &1D15, &2D25, &3D35
        DW      &0E06, &1E16, &2E26, &3E36, &0E06, &1E16, &2E26, &3E36
        DW      &0E06, &1E16, &2E26, &3E36, &0E06, &1E16, &2E26, &3E36
        DW      &0F07, &1F17, &2F27, &3F37, &0F07, &1F17, &2F27, &3F37
        DW      &0F07, &1F17, &2F27, &3F37, &0F07, &1F17, &2F27, &3F37

TabPen0:
        DB      &77, &00, &BB, &00, &DD, &00, &EE, &00
        DB      &77, &80, &BB, &40, &DD, &20, &EE, &10
        DB      &77, &08, &BB, &04, &DD, &02, &EE, &01
        DB      &77, &88, &BB, &44, &DD, &22, &EE, &11
       
TabPen:
        DS      2

InitGfxLib:
        LD      BC,&BC01
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg1 = 32 (256 pixels width)
        OUT  (C),C
        LD      BC,&BC02
        OUT     (C),C
        LD      BC,&BD2A                ; Center the screen horizontally
        OUT     (C),C
        LD      BC,&BC06
        OUT     (C),C
        LD      BC,&BD20                ; CRTC reg6 = 32 (256 pixels height)
        OUT     (C),C
        LD      BC,&BC07
        OUT     (C),C
        LD      BC,&BD22                ; Center the screen vertically
        OUT     (C),C

__endasm;
}

void setColor(unsigned char color) {
color;
__asm
        LD      A,(IX+4)
        AND     3
        ADD     A,A
        ADD     A,A
        ADD     A,A
        LD      H,TabPen0/256
        LD      L,A
        LD      (TabPen),HL
__endasm;
}

void drawLine(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2) {
x1;x2;y1;y2;
__asm
; B = X1
; C = Y1
; D = X2
; E = Y2
        LD      A,(IX+10)               ; y2
        LD      C,(IX+6)                ; y1
        CP      C
        JP      Z,drawLineHor
        LD      B,(IX+4)                ; x1
        LD      D,(IX+8)                ; x2
        LD      E,A                     ; y2
        LD      HL,(TabPen)
        LD      (drawLineCoul+1),HL
        LD      A,E
        SUB     C
        JR      NC,drawLineTst1
        NEG
drawLineTst1:
        LD      H,A                     ; H = Abs(Y2-Y1)
        LD      A,D
        SUB     B
        JR      NC,drawLineTst2
        NEG
drawLineTst2:
        CP      H                       ; A=Abs(X2-X1) CP Abs(Y2-Y1)
        JR      C,drawLineV             ; Si A>=H -> Ligne par laxe horizontal
        LD      A,B
        LD      B,C
        LD      C,A                     ; Inversion X1 et Y1
        LD      A,D
        LD      D,E
        LD      E,A                     ; Inversion X2 et Y2
        LD      A,&68                   ; LD L,B
        LD      (drawLineOrd1),A
        LD      A,&79                   ; LD A,C
        JR      drawLine1
drawLineV:
        LD      A,&69                   ; LD L,C
        LD      (drawLineOrd1),A
        LD      A,&78                   ; LD A,B
drawLine1:
        LD      (drawLineAbs1),A
        LD      (drawLineAbs2),A
        LD      A,E
        CP      C
        JR      NC,drawLine2
        LD      E,C
        LD      C,A                     ; Echange Y1 et Y2
        LD      A,D
        lD      D,B
        LD      B,A                     ; Echange X1 et X2
drawLine2:
        LD      A,D
        SUB     B
        LD      L,&04                   ; INC B
        JR      NC,drawLine3
        NEG
        INC     L                       ; DEC B
drawLine3:
        EX      AF,AF'                  ; Stockage DX
        LD      A,L
        LD      (drawLineXincr),A       ; Stockage INC ou DEC B
        LD      A,C
        SUB     E
        EXX
        LD      E,A                     ; Stockage -DY
        LD      D,&FF
        EX      AF,AF'                  ; Récupère DX
        LD      L,A                     ; L = DX
        LD      H,&00
        ADD     HL,HL                   ; DX * 2
        LD      B,H
        LD      C,L                     ; Bincr = DX * 2 (BC)
        ADD     HL,DE                   ; - DY
        ADD     HL,DE                   ; - DY
        EX      DE,HL                   ; Aincr = DX * 2 - DY * 2 (DE)
        ADD     HL,BC                   ; delta = DX * 2 - DY
        EXX
        LD      A,E                     ; Récupère Y2
        ;
        ; faire un point aux coordonnées X(Reg.B), Y(Reg.C) OU Y,X
        ;
drawLineBcl:
        EX      AF,AF'                  ; Sauvegarde Y2
        LD      H,TabAdrEcr/256
drawLineOrd1:
        LD      L,C                     ; y to plot
drawLineAbs1:
        LD      A,B
        AND     A
        RRA
        AND     A
        RRA                             ; x/4
        ADD     A,(HL)
        LD      E,A
        INC     H                       ; Adresse des poids forts
        LD      A,(HL)
drawLineOffsetVideo:
        ADC     A,&C0
        LD      D,A                     ; Reg.DE = adresse mémoire écran (0,y)
drawLineAbs2:
        LD      A,B
        AND     3
        RLA
drawLineCoul:
        LD      HL,0
        ADD     A,L
        LD      L,A
        LD      A,(DE)                  ; Octet mémoire écran
        AND     (HL)                    ; Masque
        INC     L
        OR      (HL)                    ; Octet à écrire en mémoire écran
        LD      (DE),A
        EX      AF,AF'                  ; Récupère Y2
        INC     C                       ; Incrémenter Y1
        EXX
        BIT     7,H                     ; Delta négatif ?
        JR      Z,drawLineAincr
drawLineBincr:
        ADD     HL,BC                   ; Delta += Bincr
        EXX
        CP      C                       ; compare Y2 à Y1
        JR      NZ,drawLineBcl
        JR      drawLineDone
drawLineAincr:
        ADD     HL,DE                   ; Delta += Aincr
        EXX
drawLineXincr:
        INC     B                       ; ou dec b
        CP      C                       ; compare Y2-Y1
        JR      NZ,drawLineBcl
        JR      drawLineDone

drawLineHor:
        LD      A,(IX+4)                ; x1
        LD      E,A
        LD      A,(IX+8)                ; x2
        SUB     E
        RET     Z
        RET     C
        LD      (DrawLigneHor3+1),A     ; x2- x1
        LD      HL,(TabPen)
        LD      (DrawLigneHor1+1),HL
        LD      A,(HL)
        LD      (DrawLigneHor7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (DrawLigneHor6+1),A
        LD      L,(IX+6)                ; LineY
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
DrawLigneHor1:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
DrawLigneHor2:
        AND     A
        JR      Z,DrawLigneHor3
        RRC     C
        DEC     B
        DEC     A
        JR      DrawLigneHor2
DrawLigneHor3:
        LD      DE,0
DrawLigneHor4:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    DrawLigneHor8
        LD      A,E
DrawLigneHor5:
        INC     HL
        SUB     5
        JR      C,DrawLigneHor7
        INC     A
        LD      E,A
DrawLigneHor6:
        LD      (HL),0
        AND     A
        JR      Z,drawLineDone
        JR      DrawLigneHor5
DrawLigneHor7:
        LD      BC,&400
DrawLigneHor8:
        DEC     E
        JR      NZ,DrawLigneHor4
drawLineDone:
__endasm;
}

void fillRect(unsigned short x1, unsigned short y1, unsigned short width, unsigned short height) {
x1;y1;width;height;
__asm
        LD      A,(IX+4)
        OR      (IX+6)
        JR      NZ,fillRectInit
        LD      A,(IX+8)
        AND     (IX+10)
        CP      &FF
        JR      Z,fillFullScreen
fillRectInit:
        LD      HL,(TabPen)
        LD      (fillRectPen+1),HL
        INC     HL
        LD      A,(HL)
        LD      (fillRect7+1),A
        LD      C,A
        RRCA
        OR      C
        RRCA
        OR      C
        RRCA
        OR      C
        LD      (fillRect5+1),A
        LD      A,(IX+4)                ; x1
        LD      (fillRectBcl+1),A
        LD      L,(IX+6)                ; y1
        LD      A,(IX+8)                ; width
        LD      (fillRect2+1),A
        LD      H,(IX+10)               ; height
fillRectBcl:
        LD      E,0                     ; rectX1
        PUSH    HL                      ; H = height, L = y1
        LD      BC,&C007                ; C0 = high byte of mem video, 07 = mask
        LD      A,L                     ; y to plot
        AND     C
        LD      H,A
        XOR     L
        LD      L,A
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        LD      A,E                     ; x to plot
        AND     3
        LD      D,A                     ; D = NumPixel
        LD      A,E
        RRA
        AND     A
        RRA
        LD      C,A                     ; x/4
        ADD     HL,BC                   ; B = high byte of mem video, C = x/4
        EX      DE,HL
        LD      C,H
fillRectPen:
        LD      HL,0
        LD      B,(HL)
        LD      A,C
        AND     3
        LD      C,B
        EX      DE,HL                   ; HL = screen adr
        LD      B,4
fillRect1:
        AND     A
        JR      Z,fillRect2
        RRC     C
        DEC     B
        DEC     A
        JR      fillRect1
fillRect2:
        LD      DE,0
fillRect3:
        LD      A,(HL)
        OR      C
        LD      (HL),A
        RRC     C
        DJNZ    fillRect8
        LD      A,E
fillRect4:
        INC     HL
        SUB     5
        JR      C,fillRect7
        INC     A
        LD      E,A
fillRect5:
        LD      (HL),0
        AND     A
        JR      Z,fillRect9
        JR      fillRect4
fillRect7:
        LD      BC,&400
fillRect8:
        DEC     E
        JR      NZ,fillRect3
fillRect9:
        POP     HL
        INC     L
        DEC     H
        JR      NZ,fillRectBcl
        JR     fillRectDone

fillFullScreen:
        LD      HL,(TabPen)
        INC     HL
        LD      A,(HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR     (HL)
        INC     HL
        INC     HL
        OR      (HL)
        LD      L,A
        LD      H,A
        LD      (fillFullScreenSP+1),SP
        LD      SP,0
        LD      B,0
fillFullScreenBcl:
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        PUSH    HL
        DJNZ    fillFullScreenBcl
fillFullScreenSP:
        LD    SP,0

fillRectDone:
__endasm;
}


demoniak

I think I should make a "fast vertical line" to speed up this test  :D

mr_lou

#22
Quote from: demoniak on 12:24, 29 December 11
I think I should make a "fast vertical line" to speed up this test  :D

I didn't know that was possible.
Please, build on the sMIDP2lib.h file above, so I don't have to make those minor changes again.  :)

Meanwhile, can someone explain to me why I can't RUN"SDCC after I LOAD"BASIC ?
In other words. SDCC.BIN will only run if there's nothing else in memory when I load it? Why? Can it be resolved?

demoniak

#23
Here is the version with "fast vertical lines"

mr_lou

The vertical lines doesn't seem faster to me? But I did have to change two JR's to JP's.

Powered by SMFPacks Menu Editor Mod