Author Topic: drawing lines with cpcTelera / SDCC (V1.0 RELEASE)  (Read 5831 times)

0 Members and 1 Guest are viewing this topic.

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Hi folks.

Wow, has that much time passed since my last CPC project?!?!
I've been away from the scene a bit since I finished RUNCPC last year, but I guess that old itch never goes away...

One thing I've always wanted to do is mess around with drawing lines, and since cpcTelera doesn't yet have any line drawing functions, why not give it a go?
I managed to get a mode 0 Bresenham routine working quite easily, but got stuck for some time on modes 1 and 2.

Fortunately I found this wonderful article:
CPCRULEZ > CODING > SDCC TUT'S PAR STEPHBB75 > Dessiner en mode 1

With a bit of help from google translate, I was able to quickly add mode 1 & 2 to my little test program.
 8)

The attached dsk contains a binary compiled from pure SDCC (in cpcTelera), and therefore is not as fast as it will ultimately become.
I think the line drawing speeds are useful as-is for non-game applications, but for real-time situations (like games) it is too slow.

I've got quite a lot left to do.
- optimised vertical / horizontal / perfect-diagonal routines
- line clipping
- conversion of critical routines to asm

Line clipping is a tricky one.
I've researched 4 different techniques, each with their own pros and cons, but I'm not sure I want to go with any of them.
In a game, lines will likely be relatively short, so it might be more efficient to simply rush through Bresenham's without the pixel plotting, until the x,y are on-screen.

We shall see...

For anyone interested, here is the first version of the main.c source.
It's not pretty, as it's just experimenting at the moment.
I'm particularly keen on improving mode 1 and 2 speeds, but I don't really know how to yet (though I've seen hints from others - TFM? - in the past that it may be possible to use bit-level operations to really speed up mode 2).

[EDIT] There are some more tests included now. If anyone is interested in the latest source code at any time, please feel free to ask.

Code: [Select]
#include <cpctelera.h>

#define SCR_VMEM (u8*)0xC000

#define MODE0_LIMIT 159
#define MODE1_LIMIT 319
#define MODE2_LIMIT 639

void runTest();
void populate_yAddress();

void drawLine(i16,i16,i16,i16);
void drawLineMode0(i16,i16,i16,i16);
void drawLineMode1(i16,i16,i16,i16);
void drawLineMode2(i16,i16,i16,i16);

void putPixelMode0(u8,u8);
void putPixelMode1(u16,u8);
void putPixelMode2(u16,u8);

u8 const g_palette[16]={
    0x00, // black
    0x1a, // brightWhite
    0x0d, // white
    0x12, // brightGreen
    0x06, // brightRed
    0x02, // brightBlue
    0x18, // brightYellow
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
    0x00, // black
};

u8 lineColour;

u8 lineMask0_1A,lineMask0_1B;
u8 lineMask0_2A,lineMask0_2B;
u8 lineMask0_4A,lineMask0_4B;
u8 lineMask0_8A,lineMask0_8B;

u8 lineMask1_1A,lineMask1_1B,lineMask1_1C,lineMask1_1D;
u8 lineMask1_2A,lineMask1_2B,lineMask1_2C,lineMask1_2D;

u8 lineMask2_1A,lineMask2_1B,lineMask2_1C,lineMask2_1D,lineMask2_1E,lineMask2_1F,lineMask2_1G,lineMask2_1H;

u8 mode;
u8 testRun;

u8* yAddress[200];

void main(void){
    cpct_disableFirmware();

    cpct_fw2hw(g_palette,16);
    cpct_setPalette(g_palette,16);
    cpct_setBorder(g_palette[2]);

    while(1){
        runTest();

        while(1){
            cpct_scanKeyboard();

            if (cpct_isKeyPressed(Key_Esc)){
                break;
            }
        }
    }
}

void runTest(){
    i16 x,y;

    u8* pscr;

    cpct_setVideoMode(1);
    cpct_clearScreen_f64(0x00);

    pscr=cpct_getScreenPtr(SCR_VMEM,0,0);
    cpct_drawStringM1("Please select the test to run.",pscr+80+2,1,0);
    cpct_drawStringM1("(A) mode 0",pscr+240+2,1,0);
    cpct_drawStringM1("(B) mode 1",pscr+320+2,1,0);
    cpct_drawStringM1("(C) mode 2",pscr+400+2,1,0);
    cpct_drawStringM1("After the test, press ESC",pscr+560+2,1,0);
    cpct_drawStringM1("to return to this screen.",pscr+640+2,1,0);
    cpct_drawStringM1("(X) other mode 0",pscr+800+2,1,0);

    while(1){
        cpct_scanKeyboard();

        if (cpct_isKeyPressed(Key_A)){
            mode=0;
            testRun=0;
            break;
        }
        else if (cpct_isKeyPressed(Key_B)){
            mode=1;
            testRun=1;
            break;
        }
        else if (cpct_isKeyPressed(Key_C)){
            mode=2;
            testRun=2;
            break;
        }
        else if (cpct_isKeyPressed(Key_X)){
            mode=0;
            testRun=3;
            break;
        }
    }

    cpct_setVideoMode(mode);
    cpct_clearScreen_f64(0x00);

    populate_yAddress();

    // eye #1

    y=10;

    if (testRun==0){
        lineColour=3;

        for (x=8;x<=152;x+=4){
            drawLine(x,10,152,y);
            y+=5;
        }
    }
    else if (testRun==1){
        lineColour=1;

        for (x=16;x<=304;x+=8){
            drawLine(x,10,304,y);
            y+=5;
        }
    }
    else if (testRun==2){
        lineColour=1;

        for (x=32;x<=608;x+=16){
            drawLine(x,10,608,y);
            y+=5;
        }
    }

    // eye #2

    if (testRun==0){
        lineColour=4;
        x=152;

        for (y=10;y<=190;y+=5){
            drawLine(152,y,x,190);
            x-=4;
        }
    }
    else if (testRun==1){
        lineColour=3;
        x=304;

        for (y=10;y<=190;y+=5){
            drawLine(304,y,x,190);
            x-=8;
        }
    }
    else if (testRun==2){
        lineColour=1;
        x=608;

        for (y=10;y<=190;y+=5){
            drawLine(608,y,x,190);
            x-=16;
        }
    }

    // eye #3

    y=190;

    if (testRun==0){
        lineColour=5;

        for (x=152;x>=8;x-=4){
            drawLine(x,190,8,y);
            y-=5;
        }
    }
    else if (testRun==1){
        lineColour=1;

        for (x=304;x>=16;x-=8){
            drawLine(x,190,16,y);
            y-=5;
        }
    }
    else if (testRun==2){
        lineColour=1;

        for (x=608;x>=32;x-=16){
            drawLine(x,190,32,y);
            y-=5;
        }
    }

    // eye #4

    if (testRun==0){
        lineColour=6;
        x=8;

        for (y=190;y>=10;y-=5){
            drawLine(8,y,x,10);
            x+=4;
        }
    }
    else if (testRun==1){
        lineColour=3;
        x=16;

        for (y=190;y>=10;y-=5){
            drawLine(16,y,x,10);
            x+=8;
        }
    }
    else if (testRun==2){
        lineColour=1;
        x=32;

        for (y=190;y>=10;y-=5){
            drawLine(32,y,x,10);
            x+=16;
        }
    }

    if (testRun==3){
        lineColour=3;

        for (y=10;y<=190;y+=4){
            drawLine(10,y,150,y);
        }

        cpct_clearScreen_f64(0x00);
        lineColour=4;

        for (x=10;x<=150;x+=4){
            drawLine(x,10,x,190);
        }

        cpct_clearScreen_f64(0x00);
        lineColour=5;

        for (y=10;y<=70;y+=3){
            drawLine(20,y,140,y+120);
        }

        cpct_clearScreen_f64(0x00);
        lineColour=6;

        for (y=190;y>=130;y-=3){
            drawLine(20,y,140,y-120);
        }
    }
}

void populate_yAddress(){
    u8 i;

    for (i=0;i<=199;i++){
        yAddress[i]=cpct_getScreenPtr(SCR_VMEM,0,i);
    }
}

void drawLine(i16 x1,i16 y1,i16 x2,i16 y2){
    if (mode==0)
        drawLineMode0(x1,y1,x2,y2);
    else if (mode==1)
        drawLineMode1(x1,y1,x2,y2);
    else if (mode==2)
        drawLineMode2(x1,y1,x2,y2);
}

void drawLineMode0(i16 x1,i16 y1,i16 x2,i16 y2){
    i16 xn,yn;
    i16 dx,dy;

    // if line is left-x-space, discard it

    if ((x1<0) && (x2<0))
        return;

    // if line is right-x-space, discard it

    if ((x1>MODE0_LIMIT) && (x2>MODE0_LIMIT))
        return;

    // if line is above-y-space, discard it

    if ((y1<0) && (y2<0))
        return;

    // if line is below-y-space, discard it

    if ((y1>199) && (y2>199))
        return;

    // determine colour masks for mode 0

    if (lineColour&1){
        lineMask0_1A=128;
        lineMask0_1B=64;
    }
    else{
        lineMask0_1A=0;
        lineMask0_1B=0;
    }

    if (lineColour&2){
        lineMask0_2A=8;
        lineMask0_2B=4;
    }
    else{
        lineMask0_2A=0;
        lineMask0_2B=0;
    }

    if (lineColour&4){
        lineMask0_4A=32;
        lineMask0_4B=16;
    }
    else{
        lineMask0_4A=0;
        lineMask0_4B=0;
    }

    if (lineColour&{
        lineMask0_8A=2;
        lineMask0_8B=1;
    }
    else{
        lineMask0_8A=0;
        lineMask0_8B=0;
    }

    // single pixel

    if ((x1==x2) && (y1==y2)){
        putPixelMode0(x1,y1);
        return;
    }

    // swap endpoints if necessary

    if (x1>x2){
        x1^=x2;
        x2^=x1;
        x1^=x2;

        y1^=y2;
        y2^=y1;
        y1^=y2;
    }

    dx=x2-x1;
    dy=y2-y1;

    // line going down?

    if (dy>=0){
        // gentle line?
        // octant 7/3

        if (dy<=dx){
            yn=dx>>1;

            // plot valid pixels

            for (x1=x1;x1<=x2;x1++){
                putPixelMode0(x1,y1);
                yn+=dy;

                if (yn>=dx){
                    yn-=dx;
                    y1++;
                }
            }
        }

        // steep line?
        // octant 6/2

        else{
            xn=dy>>1;

            for (y1=y1;y1<=y2;y1++){
                putPixelMode0(x1,y1);
                xn+=dx;

                if (xn>=dy){
                    xn-=dy;
                    x1++;
                }
            }
        }
    }

    // line going up?

    else{
        // gentle line?
        // octant 0/4

        if (-dy<=dx){
            yn=dx>>1;

            for (x1=x1;x1<=x2;x1++){
                putPixelMode0(x1,y1);
                yn+=-dy;

                if (yn>=dx){
                    yn-=dx;
                    y1--;
                }
            }
        }

        // steep line?
        // octant 1/5

        else{
            xn=-dy>>1;

            for (y1=y1;y1>=y2;y1--){
                putPixelMode0(x1,y1);
                xn+=dx;

                if (xn>=-dy){
                    xn-=-dy;
                    x1++;
                }
            }
        }
    }
}

void drawLineMode1(i16 x1,i16 y1,i16 x2,i16 y2){
    i16 xn,yn;
    i16 dx,dy;

    // if line is left-x-space, discard it

    if ((x1<0) && (x2<0))
        return;

    // if line is right-x-space, discard it

    if ((x1>MODE1_LIMIT) && (x2>MODE1_LIMIT))
        return;

    // if line is above-y-space, discard it

    if ((y1<0) && (y2<0))
        return;

    // if line is below-y-space, discard it

    if ((y1>199) && (y2>199))
        return;

    // determine colour masks for mode 1

    if (lineColour&1){
        lineMask1_1A=128;
        lineMask1_1B=64;
        lineMask1_1C=32;
        lineMask1_1D=16;
    }
    else{
        lineMask1_1A=0;
        lineMask1_1B=0;
        lineMask1_1C=0;
        lineMask1_1D=0;
    }

    if (lineColour&2){
        lineMask1_2A=8;
        lineMask1_2B=4;
        lineMask1_2C=2;
        lineMask1_2D=1;
    }
    else{
        lineMask1_2A=0;
        lineMask1_2B=0;
        lineMask1_2C=0;
        lineMask1_2D=0;
    }

    // single pixel

    if ((x1==x2) && (y1==y2)){
        putPixelMode1(x1,y1);
        return;
    }

    // swap endpoints if necessary

    if (x1>x2){
        x1^=x2;
        x2^=x1;
        x1^=x2;

        y1^=y2;
        y2^=y1;
        y1^=y2;
    }

    dx=x2-x1;
    dy=y2-y1;

    // line going down?

    if (dy>=0){
        // gentle line?
        // octant 7/3

        if (dy<=dx){
            yn=dx>>1;

            // plot valid pixels

            for (x1=x1;x1<=x2;x1++){
                putPixelMode1(x1,y1);
                yn+=dy;

                if (yn>=dx){
                    yn-=dx;
                    y1++;
                }
            }
        }

        // steep line?
        // octant 6/2

        else{
            xn=dy>>1;

            for (y1=y1;y1<=y2;y1++){
                putPixelMode1(x1,y1);
                xn+=dx;

                if (xn>=dy){
                    xn-=dy;
                    x1++;
                }
            }
        }
    }

    // line going up?

    else{
        // gentle line?
        // octant 0/4

        if (-dy<=dx){
            yn=dx>>1;

            for (x1=x1;x1<=x2;x1++){
                putPixelMode1(x1,y1);
                yn+=-dy;

                if (yn>=dx){
                    yn-=dx;
                    y1--;
                }
            }
        }

        // steep line?
        // octant 1/5

        else{
            xn=-dy>>1;

            for (y1=y1;y1>=y2;y1--){
                putPixelMode1(x1,y1);
                xn+=dx;

                if (xn>=-dy){
                    xn-=-dy;
                    x1++;
                }
            }
        }
    }
}

void drawLineMode2(i16 x1,i16 y1,i16 x2,i16 y2){
    i16 xn,yn;
    i16 dx,dy;

    // if line is left-x-space, discard it

    if ((x1<0) && (x2<0))
        return;

    // if line is right-x-space, discard it

    if ((x1>MODE2_LIMIT) && (x2>MODE2_LIMIT))
        return;

    // if line is above-y-space, discard it

    if ((y1<0) && (y2<0))
        return;

    // if line is below-y-space, discard it

    if ((y1>199) && (y2>199))
        return;

    // determine colour masks for mode 2

    if (lineColour&1){
        lineMask2_1A=128;
        lineMask2_1B=64;
        lineMask2_1C=32;
        lineMask2_1D=16;
        lineMask2_1E=8;
        lineMask2_1F=4;
        lineMask2_1G=2;
        lineMask2_1H=1;
    }
    else{
        lineMask2_1A=0;
        lineMask2_1B=0;
        lineMask2_1C=0;
        lineMask2_1D=0;
        lineMask2_1E=0;
        lineMask2_1F=0;
        lineMask2_1G=0;
        lineMask2_1H=0;
    }

    // single pixel

    if ((x1==x2) && (y1==y2)){
        putPixelMode2(x1,y1);
        return;
    }

    // swap endpoints if necessary

    if (x1>x2){
        x1^=x2;
        x2^=x1;
        x1^=x2;

        y1^=y2;
        y2^=y1;
        y1^=y2;
    }

    dx=x2-x1;
    dy=y2-y1;

    // line going down?

    if (dy>=0){
        // gentle line?
        // octant 7/3

        if (dy<=dx){
            yn=dx>>1;

            // plot valid pixels

            for (x1=x1;x1<=x2;x1++){
                putPixelMode2(x1,y1);
                yn+=dy;

                if (yn>=dx){
                    yn-=dx;
                    y1++;
                }
            }
        }

        // steep line?
        // octant 6/2

        else{
            xn=dy>>1;

            for (y1=y1;y1<=y2;y1++){
                putPixelMode2(x1,y1);
                xn+=dx;

                if (xn>=dy){
                    xn-=dy;
                    x1++;
                }
            }
        }
    }

    // line going up?

    else{
        // gentle line?
        // octant 0/4

        if (-dy<=dx){
            yn=dx>>1;

            for (x1=x1;x1<=x2;x1++){
                putPixelMode2(x1,y1);
                yn+=-dy;

                if (yn>=dx){
                    yn-=dx;
                    y1--;
                }
            }
        }

        // steep line?
        // octant 1/5

        else{
            xn=-dy>>1;

            for (y1=y1;y1>=y2;y1--){
                putPixelMode2(x1,y1);
                xn+=dx;

                if (xn>=-dy){
                    xn-=-dy;
                    x1++;
                }
            }
        }
    }
}

void putPixelMode0(u8 nX,u8 nY){
    u8* vram=yAddress[nY]+(nX>>1);
    u8 remainder=nX%2;

    if(remainder==0)
        *vram=((((*vram&85)|lineMask0_1A)|lineMask0_2A)|lineMask0_4A)|lineMask0_8A;
    else
        *vram=((((*vram&170)|lineMask0_1B)|lineMask0_2B)|lineMask0_4B)|lineMask0_8B;
}

void putPixelMode1(u16 nX,u8 nY){
    u8* vram=yAddress[nY]+(nX>>2);
    u8 remainder=nX-((nX>>2)<<2);

    if(remainder==0)
        *vram=((*vram&=119)|lineMask1_1A)|lineMask1_2A;
    else if(remainder==1)
        *vram=((*vram&=187)|lineMask1_1B)|lineMask1_2B;
    else if(remainder==2)
        *vram=((*vram&=221)|lineMask1_1C)|lineMask1_2C;
    else
        *vram=((*vram&=238)|lineMask1_1D)|lineMask1_2D;
}

void putPixelMode2(u16 nX,u8 nY){
    u8* vram=yAddress[nY]+(nX>>3);
    u8 remainder=nX-((nX>>3)<<3);

    if(remainder==0)
        *vram=(*vram&=127)|lineMask2_1A;
    else if(remainder==1)
        *vram=(*vram&=191)|lineMask2_1B;
    else if(remainder==2)
        *vram=(*vram&=223)|lineMask2_1C;
    else if(remainder==3)
        *vram=(*vram&=239)|lineMask2_1D;
    else if(remainder==4)
        *vram=(*vram&=247)|lineMask2_1E;
    else if(remainder==5)
        *vram=(*vram&=251)|lineMask2_1F;
    else if(remainder==6)
        *vram=(*vram&=253)|lineMask2_1G;
    else
        *vram=(*vram&=254)|lineMask2_1H;
}
« Last Edit: 06:12, 14 December 16 by ervin »
RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline arnoldemu

  • Supporter
  • 6128 Plus
  • *
  • Posts: 5.031
  • Country: gb
    • Unofficial Amstrad WWW Resource
  • Liked: 1921
Re: drawing lines with cpcTelera / SDCC
« Reply #1 on: 15:05, 19 July 16 »
Elite on BBC (not sure about CPC) used different line drawing methods depending on angle and length. You may find the same works good for you too.

In my unreleased rom game I drew lines and clipped them but the frame rate wasn't great (but then I was also doing some 3d calculations and the game stalled because of conversion between different coordinate systems and different fixed point representations).

I hope you do better :)



My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Re: drawing lines with cpcTelera / SDCC
« Reply #2 on: 15:07, 19 July 16 »
Interesting... I didn't know that about BBC Elite.

I've actually been wondering about your vector game - I've been looking forward to it for a long time.
Do you have any plans to revisit it?
RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline arnoldemu

  • Supporter
  • 6128 Plus
  • *
  • Posts: 5.031
  • Country: gb
    • Unofficial Amstrad WWW Resource
  • Liked: 1921
Re: drawing lines with cpcTelera / SDCC
« Reply #3 on: 21:59, 19 July 16 »
Interesting... I didn't know that about BBC Elite.
ELITE by David Braben (Frontier Developments) Game - coffee and tea

I've actually been wondering about your vector game - I've been looking forward to it for a long time.
Do you have any plans to revisit it?
Yes but later in the year.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Re: drawing lines with cpcTelera / SDCC
« Reply #4 on: 03:14, 20 July 16 »
ELITE by David Braben (Frontier Developments) Game - coffee and tea
Yes but later in the year.


Excellent, really looking forward to seeing what you come up with.
 8)

RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Re: drawing lines with cpcTelera / SDCC
« Reply #5 on: 06:40, 20 July 16 »
Alrighty, optimised routines for vertical, horizontal and 1:1 diagonal lines are done.
Now it's time to open the doors to the scary world of line clipping!
 :o
RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Re: drawing lines with cpcTelera / SDCC
« Reply #6 on: 08:10, 20 July 16 »
Quick question for everyone...
Do you think that (0,0) should be at the top-left of the screen, or at the bottom-left (in terms of pixels)?

BASIC uses the bottom-left, so I'm inclined to go with that.
It's the opposite to what screen address calculations give, but it's trivial to adjust the y coordinates to work the same way as they do in BASIC.

[EDIT] Actually, I've decided to go with top-left. That seems to be generally accepted these days as the default origin.
 8)
« Last Edit: 08:22, 20 July 16 by ervin »
RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline roudoudou

  • CPC6128
  • ****
  • Posts: 255
  • Country: fr
    • urban exploration
  • Liked: 225
Re: drawing lines with cpcTelera / SDCC
« Reply #7 on: 10:07, 20 July 16 »
- conversion of critical routines to asm



Before converting critical routines to asm, you have to optimise the algorithm.


The heavy part is the call to PutPixel.


But before remove the PutPixel, you must do the full clipping to be sure every pixels you will write will be on screen


If you ensure to always draw from top to bottom, then you have only two cases:
- step down and sometimes go to the left
- step down and sometimes go the the right


So the PutPixel routine becomes:
- init: compute the starting adress on screen and the starting mask (with the current position in the byte, 0/1 in mode 0, 0/1/2/3 in mode 1, 0/1/2/3/4/5/6/7 in mode 2)
- routine1: put pixel to current adress / jump to next line OR shift color mask (it's the same thing to do in all video mode, shifting) and possibly DECrease current adress when the position in the byte exceed 1,3 or 7*

- routine2: put pixel to current adress / jump to next line OR shift color mask (it's the same thing to do in all video mode, shifting) and possibly INCrease current adress when the position in the byte exceed 1,3 or 7*


I suggest to use a counter decrementing for both routines -> faster, you do not have to compare either test zero after dec.


--- this will be a huge work! ---


Once you've optimized the critical part of the algorithm, you may get some additionnal speed improvement with a native assembly code.


Finally, you will also trade all the clumsy code like the swapping coordinates (i have not red all the source but this one is absolutely not clever)
x1^=x2; x2^=x1; x1^=x2 (...)  -> use a temporary variable tmp=x1;x1=x2;x2=tmp; cause it's faster, and in assembly (maybe with the compile code too) will not require a tmp variable but a temporary register and will NOT compute the XOR for nothing.
use RASM, the best assembler ever made :p

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 988
  • Country: au
    • index.php?action=treasury
  • Liked: 646
Re: drawing lines with cpcTelera / SDCC
« Reply #8 on: 10:35, 20 July 16 »
@roudoudou
That's brilliant information and advice.
Thanks so much for all of that.
I'll study your suggestions and try to incorporate them.
RUNCPC
My entry for the CPCRetroDev 2015 Competition
http://www.pouet.net/prod.php?which=66566

FAST line drawing in CPCtelera
http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.256
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 549
Re: drawing lines with cpcTelera / SDCC
« Reply #9 on: 12:17, 20 July 16 »
Quick question for everyone...
Do you think that (0,0) should be at the top-left of the screen, or at the bottom-left (in terms of pixels)?

BASIC uses the bottom-left, so I'm inclined to go with that.
It's the opposite to what screen address calculations give, but it's trivial to adjust the y coordinates to work the same way as they do in BASIC.

[EDIT] Actually, I've decided to go with top-left. That seems to be generally accepted these days as the default origin.
 8)


I don't know because I noticed you weren't using the Firmware, the Graphics used in BASIC come from the Firmware, so when something else is implemented (e.g. @Executioner Fast plot), all the graphical co-ordinates change.