Dark Bit Factory & Gravity

PROGRAMMING => Freebasic => Topic started by: Shockwave on May 12, 2007

Title: Coding Excersise. 3D Starfields.
Post by: Shockwave on May 12, 2007
I promised a long time ago that I was going to do lots of stuff like this, as it happens I am sat at home twiddling my thumbs and I needed to code a 3D starfield for something I am writing, so before I tart it upo and add lots of stuff to it I decided to make it in simple form first and turn it into a mini-challenge / excersise for novice to intermediate freebasic users.

I've got four challenges for you, two are for novice and intermediate users and two are for intermediate users.

Of course feel free to have a go at all three anyway!!!

For the first person to solve each challenge, there's 2 Karma on offer for each one.

Novice challenges;

1: Make the starfield move in and out of the screen.. Hint! Use a little bit of sin ;)
2: Make the starfield Move up and down, again use some sin and cos.

Intermediate challenges;

1: If left in it's current state (with no movement up and down) there is a deliberate logical bug in this code. You might have to study it for a while to identify the bug which may never ever occur, but it is a possibility. Identify the bug and fix the code!
2: Taking the starfield in it's current state, add one axis of rotation to it.

All that remains is to post the code. I've fully commented it, enjoy!

Code: [Select]

' Very simple program to make a 3D starfield. This is designed to be as easy
' as possible for nivices and intermediate level coders to understand.
' I recommend that you upgrade tinyptc to use rbraz's library before you run this.
'
' The listing is comprehensively commented, any questions / comments you have,
' please post them.
'
' This also contains a deliberate and very subtle logical bug that you will
' only be able to work out if you fully understand this listing!
' There is also a more obvious bug too.
' Please see the comments in the post.
' Enjoy and use freely, by Shockwave^S!P
' This code may not be posted on other web sites without my written permission.
' www.dbfinteractive.com

'-------------------------------------------------------------------------
' CONSTANTS;
'-------------------------------------------------------------------------

    CONST   XRES    =   640:'            SCREEN WIDTH
    CONST   YRES    =   480:'            SCREEN HEIGHT

'-------------------------------------------------------------------------
' FIXED SIZE ARRAYS, DEFINE >ALL< VARIABLES;
'-------------------------------------------------------------------------

    OPTION STATIC
    OPTION EXPLICIT

'-------------------------------------------------------------------------
' INCLUDES;
'-------------------------------------------------------------------------

  '  #DEFINE PTC_WIN
    #INCLUDE ONCE  "TINYPTC.BI"

'-------------------------------------------------------------------------
' SCREEN BUFFER;
'-------------------------------------------------------------------------

    DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )

'-------------------------------------------------------------------------
' OPEN SCREEN
'-------------------------------------------------------------------------

    If( ptc_open( "AS SIMPLE AS IT GETS", XRES, YRES ) = 0 ) Then
    End -1
    End If

'-------------------------------------------------------------------------
' PROGRAM VARIABLES;
'-------------------------------------------------------------------------

    DIM SHARED AS INTEGER HALFX,HALFY
   
                          HALFX=XRES/2:' SIMPLE OPTIMISATIONS TO SAVE 2 DIVIDES
                          HALFY=YRES/2:' PER STAR LATER ON.

    DIM SHARED AS INTEGER STNM = 1000 :' HOW MANY STARS TO HAVE.
   
    DIM SHARED AS DOUBLE  STX(STNM):'    STORES STAR X POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STY(STNM):'    STORES STAR Y POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STZ(STNM):'    STORES STAR Z POS 3D CO-ORDINATE

'-------------------------------------------------------------------------
' SUBROUTINES;
'-------------------------------------------------------------------------

    DECLARE SUB SETUP_STARS():'          WILL SET UP INITIAL POSITIONS.
    DECLARE SUB STARFIELD():'            WILL BE USED TO DRAW THE STARS.
   
    SETUP_STARS():'                      CREATE SOME STAR POSITIONS.
   
'------------------------------------------------------------------------
' MAIN LOOP ( LOOP FOREVER :-P )
'------------------------------------------------------------------------

    WHILE(1)
       
       
        STARFIELD():'                    CALL THE STARFIELD ROUTINE.
        PTC_UPDATE@BUFFER(0):'           UPDATE THE SCREEN BUFFER.
        ERASE BUFFER:'                   CLEAR THE BUFFER AND .:. THE SCREEN.
   
   
    WEND
    END
   
'------------------------------------------------------------------------
' STARFIELD
'------------------------------------------------------------------------

SUB STARFIELD()
   
DIM AS INTEGER L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)


' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
   
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX =( STX(L)/STZ(L) ) + HALFX:' TRANSFORM 3D X TO 2D X
        TY =( STY(L)/STZ(L) ) + HALFY:' TRANSFORM 3D Y TO 2D Y
       
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
        ' AND THEN MOVE IT A LITTLE BIT CLOSER FOR NEXT TIME WE LOOK AT IT.
       
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES THEN
           
            CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
            '                               CALCULATED BY REVERSING THE SIGN OF Z
            '                               AND THEN BRINGING INTO RANGE AND FINALLY
            '                               MULTIPLYING BY 10 SO IT ENDS UP
            '                               BETWEEN 0 AND 250
           
            BUFFER (TX+(TY*XRES)) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
           
            STZ(L) = STZ(L)-.1:'                     MOVE IT IN A LITTLE
           
           
        ELSE
           
           
            ' IF THE STAR IS NOT ON THE SCREEN WE SET THE Z POS INTO
            ' THE DISTANCE AND GENERATE NEW X AND Y POSITIONS BECAUSE IT HAS GONE
            ' OUT OF VIEW.             
           
            STZ(L) =  25:'                   SET MAXIMUM DEPTH
            STX(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
            STY(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
           
           
        END IF
       
    NEXT

END SUB

'------------------------------------------------------------------------
' INITIALISE STARS
'------------------------------------------------------------------------

SUB SETUP_STARS()
    DIM L AS INTEGER :'                   LOOP COUNTER
   
    '                                     LOOP THROUGH EACH STAR IN TURN
    '                                     REMEMBER THAT STNM HOLDS THE AMOUNT OF STARS.
   
    FOR L=1 TO STNM
       
        STX(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STY(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STZ(L) = RND(1)*25:'             GENERATE AND STORE A NUMBER BETWEEN 0 AND + 25
       
    NEXT
   
END SUB
Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 12, 2007
right for the intermidiate part1 of the challenge heres what im thinking that because you were basing your conditional check on the x and y position there was a chance of a divide by 0 on the z.

and here is one possible fix to regenerate the star based on its z value is that right?.


Code: [Select]
SUB STARFIELD()
   
DIM AS INTEGER L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)


' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
   
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX =( STX(L)/STZ(L) ) + HALFX:' TRANSFORM 3D X TO 2D X
        TY =( STY(L)/STZ(L) ) + HALFY:' TRANSFORM 3D Y TO 2D Y
       
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
        ' AND THEN MOVE IT A LITTLE BIT CLOSER FOR NEXT TIME WE LOOK AT IT.
       
       
           
        CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
        '                               CALCULATED BY REVERSING THE SIGN OF Z
        '                               AND THEN BRINGING INTO RANGE AND FINALLY
        '                               MULTIPLYING BY 10 SO IT ENDS UP
        '                               BETWEEN 0 AND 250 
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES THEN
                BUFFER (TX+(TY*XRES)) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
        ENDIF
   
        IF STZ(L)>1 THEN
           
            STZ(L) = STZ(L)-.1:'                     MOVE IT IN A LITTLE
           
           
        ELSE
           
           
            ' IF THE STAR IS NOT ON THE SCREEN WE SET THE Z POS INTO
            ' THE DISTANCE AND GENERATE NEW X AND Y POSITIONS BECAUSE IT HAS GONE
            ' OUT OF VIEW.             
           
            STZ(L) =  25:'                   SET MAXIMUM DEPTH
            STX(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
            STY(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
           
           
        END IF
       
    NEXT

END SUB

now about the rotation do you mean that i could spin the stars on any axis x,y or z?
Title: Re: Coding Excersise. 3D Starfields.
Post by: Shockwave on May 12, 2007
Any axis would do Nino :)

Unfortunately that's not the bug. A divide by zero in this program would cause no ill effects.
Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 12, 2007
bugger ill have to have a closser squint at it me thinks!

hows about this for the x and y axis`s.
Code: [Select]
'------------------------------------------------------------------------
' STARFIELD
'------------------------------------------------------------------------
dim shared as double angle
SUB STARFIELD()
   
DIM AS double L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)
DIM AS DOUBLE xx,xy

' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
    angle +=0.1
   
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX = cast( integer , ( STX(L)/STZ(L) ) + HALFX )' TRANSFORM 3D X TO 2D X
        TY = cast( integer , ( STY(L)/STZ(L) ) + HALFY )' TRANSFORM 3D Y TO 2D Y
       
       
        xx = sin( (angle) / 180*3.141 )* 250.0
        xy = cos( (angle) / 180*3.141 )* 250.0
       
       
        tx += cast( integer , xx )
        ty += cast( integer , xy )
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
        ' AND THEN MOVE IT A LITTLE BIT CLOSER FOR NEXT TIME WE LOOK AT IT.
       
       
           
        CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
        '                               CALCULATED BY REVERSING THE SIGN OF Z
        '                               AND THEN BRINGING INTO RANGE AND FINALLY
        '                               MULTIPLYING BY 10 SO IT ENDS UP
        '                               BETWEEN 0 AND 250 
        IF tX>0 AND tX<XRES AND tY>0 AND tY<YRES THEN
                BUFFER ( tX + ( tY*XRES ) ) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
        ENDIF
   
        IF STZ(L)>1 THEN
           
            STZ(L) = STZ(L)-.1:'                     MOVE IT IN A LITTLE
           
           
        ELSE
           
           
            ' IF THE STAR IS NOT ON THE SCREEN WE SET THE Z POS INTO
            ' THE DISTANCE AND GENERATE NEW X AND Y POSITIONS BECAUSE IT HAS GONE
            ' OUT OF VIEW.             
           
            STZ(L) =  25:'                   SET MAXIMUM DEPTH
            STX(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
            STY(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
           
           
        END IF
       
    NEXT

END SUB


good challenge btw ive had some reall fun already are there any plans for more of these in future?
Title: Re: Coding Excersise. 3D Starfields.
Post by: rain_storm on May 12, 2007
This should take care of the rotation around any axis (In this case its the Z axis) ...

Code: [Select]

' Very simple program to make a 3D starfield. This is designed to be as easy
' as possible for nivices and intermediate level coders to understand.
' I recommend that you upgrade tinyptc to use rbraz's library before you run this.
'
' The listing is comprehensively commented, any questions / comments you have,
' please post them.
'
' This also contains a deliberate and very subtle logical bug that you will
' only be able to work out if you fully understand this listing!
' There is also a more obvious bug too.
' Please see the comments in the post.
' Enjoy and use freely, by Shockwave^S!P
' This code may not be posted on other web sites without my written permission.
' www.dbfinteractive.com

'-------------------------------------------------------------------------
' CONSTANTS;
'-------------------------------------------------------------------------

    CONST   XRES    =   640:'            SCREEN WIDTH
    CONST   YRES    =   480:'            SCREEN HEIGHT
    CONST   PI = 3.14159
'-------------------------------------------------------------------------
' FIXED SIZE ARRAYS, DEFINE >ALL< VARIABLES;
'-------------------------------------------------------------------------

    OPTION STATIC
    OPTION EXPLICIT

'-------------------------------------------------------------------------
' INCLUDES;
'-------------------------------------------------------------------------

  '  #DEFINE PTC_WIN
    #INCLUDE ONCE  "TINYPTC.BI"

'-------------------------------------------------------------------------
' SCREEN BUFFER;
'-------------------------------------------------------------------------

    DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )

'-------------------------------------------------------------------------
' OPEN SCREEN
'-------------------------------------------------------------------------

    If( ptc_open( "AS SIMPLE AS IT GETS", XRES, YRES ) = 0 ) Then
    End -1
    End If

'-------------------------------------------------------------------------
' PROGRAM VARIABLES;
'-------------------------------------------------------------------------

    DIM SHARED AS INTEGER HALFX,HALFY
   
                          HALFX=XRES/2:' SIMPLE OPTIMISATIONS TO SAVE 2 DIVIDES
                          HALFY=YRES/2:' PER STAR LATER ON.

    DIM SHARED AS INTEGER STNM = 1000 :' HOW MANY STARS TO HAVE.
   
    DIM SHARED AS DOUBLE  STX(STNM):'    STORES STAR X POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STY(STNM):'    STORES STAR Y POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STZ(STNM):'    STORES STAR Z POS 3D CO-ORDINATE
    DIM shared AS SINGLE COSZ, SINZ, ROTZ

'-------------------------------------------------------------------------
' SUBROUTINES;
'-------------------------------------------------------------------------

    DECLARE SUB SETUP_STARS():'          WILL SET UP INITIAL POSITIONS.
    DECLARE SUB STARFIELD():'            WILL BE USED TO DRAW THE STARS.
   
    SETUP_STARS():'                      CREATE SOME STAR POSITIONS.
   
'------------------------------------------------------------------------
' MAIN LOOP ( LOOP FOREVER :-P )
'------------------------------------------------------------------------

    do
        STARFIELD():'                    CALL THE STARFIELD ROUTINE.
        PTC_UPDATE@BUFFER(0):'           UPDATE THE SCREEN BUFFER.
        ERASE BUFFER:'                   CLEAR THE BUFFER AND .:. THE SCREEN.
    loop until inkey$ <> ""
    ptc_close
    END
   
'------------------------------------------------------------------------
' STARFIELD
'------------------------------------------------------------------------

SUB STARFIELD()
   
DIM AS INTEGER L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)

' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
    ROTZ = ROTZ + 0.002
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX =(COS(ROTZ)*STX(L) + SIN(ROTZ)*STY(L))/STZ(L) + HALFX:' TRANSFORM 3D X TO 2D X
        TY =(COS(ROTZ)*STY(L) - SIN(ROTZ)*STX(L))/STZ(L) + HALFY:' TRANSFORM 3D Y TO 2D Y
       
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
        ' AND THEN MOVE IT A LITTLE BIT CLOSER FOR NEXT TIME WE LOOK AT IT.
       
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES THEN
           
            CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
            '                               CALCULATED BY REVERSING THE SIGN OF Z
            '                               AND THEN BRINGING INTO RANGE AND FINALLY
            '                               MULTIPLYING BY 10 SO IT ENDS UP
            '                               BETWEEN 0 AND 250
           
            BUFFER (TX+(TY*XRES)) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
           
            STZ(L) = STZ(L)-.1:'                     MOVE IT IN A LITTLE
           
           
        ELSE
           
           
            ' IF THE STAR IS NOT ON THE SCREEN WE SET THE Z POS INTO
            ' THE DISTANCE AND GENERATE NEW X AND Y POSITIONS BECAUSE IT HAS GONE
            ' OUT OF VIEW.             
           
            STZ(L) =  25:'                   SET MAXIMUM DEPTH
            STX(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
            STY(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
           
           
        END IF
       
    NEXT

END SUB

'------------------------------------------------------------------------
' INITIALISE STARS
'------------------------------------------------------------------------

SUB SETUP_STARS()
    DIM L AS INTEGER :'                   LOOP COUNTER
   
    '                                     LOOP THROUGH EACH STAR IN TURN
    '                                     REMEMBER THAT STNM HOLDS THE AMOUNT OF STARS.
   
    FOR L=1 TO STNM
       
        STX(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STY(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STZ(L) = RND(1)*25:'             GENERATE AND STORE A NUMBER BETWEEN 0 AND + 25
       
    NEXT
   
END SUB

Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 12, 2007
cool btw i think you meant

Code: [Select]
TX =(COS(ROTZ/180*3.14159)*STX(L) + SIN(ROTZ/180*3.14159)*STY(L))/STZ(L) + HALFX:' TRANSFORM 3D X TO 2D X
TY =(COS(ROTZ/180*3.14159)*STY(L) - SIN(ROTZ/180*3.14159)*STX(L))/STZ(L) + HALFY:' TRANSFORM 3D Y TO 2D Y
Title: Re: Coding Excersise. 3D Starfields.
Post by: rain_storm on May 12, 2007
I used 0.02 instead which is just over one degree (1 degree = 0.01745) so multiplying rotz by pi and dividing by 180 would make the rate of rotation about 0.001 degree which may look better

Edit -

Yeah your right less than a degree of rotation looks way better I will change that to 0.002 instead
Title: Re: Coding Excersise. 3D Starfields.
Post by: rain_storm on May 12, 2007
Hey Shocky you say that the bug may never show up is this because the stars are only replotted when they pass over the edges of the screen (x or y axis) there is no such check for the z axis so if the star just happens to be in the exact center of the screen it well never be replotted and will appear to be motionless. Of course the fact that the stars are always plotted between -5000 & +5000 for both x and y the likelyhood of this occurring is 1 in 10,000*10,0000 (100,000,000) so we could be waiting for a while for that to happen. anyways here is a fix to that one ...

this ...
Code: [Select]
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES THEN

becomes ...
Code: [Select]
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES AND STZ(L) > 0 THEN

Hope thats it
Code: [Select]

' Very simple program to make a 3D starfield. This is designed to be as easy
' as possible for nivices and intermediate level coders to understand.
' I recommend that you upgrade tinyptc to use rbraz's library before you run this.
'
' The listing is comprehensively commented, any questions / comments you have,
' please post them.
'
' This also contains a deliberate and very subtle logical bug that you will
' only be able to work out if you fully understand this listing!
' There is also a more obvious bug too.
' Please see the comments in the post.
' Enjoy and use freely, by Shockwave^S!P
' This code may not be posted on other web sites without my written permission.
' www.dbfinteractive.com

'-------------------------------------------------------------------------
' CONSTANTS;
'-------------------------------------------------------------------------

    CONST   XRES    =   640:'            SCREEN WIDTH
    CONST   YRES    =   480:'            SCREEN HEIGHT

'-------------------------------------------------------------------------
' FIXED SIZE ARRAYS, DEFINE >ALL< VARIABLES;
'-------------------------------------------------------------------------

    OPTION STATIC
    OPTION EXPLICIT

'-------------------------------------------------------------------------
' INCLUDES;
'-------------------------------------------------------------------------

  '  #DEFINE PTC_WIN
    #INCLUDE ONCE  "TINYPTC.BI"

'-------------------------------------------------------------------------
' SCREEN BUFFER;
'-------------------------------------------------------------------------

    DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )

'-------------------------------------------------------------------------
' OPEN SCREEN
'-------------------------------------------------------------------------

    If( ptc_open( "AS SIMPLE AS IT GETS", XRES, YRES ) = 0 ) Then
    End -1
    End If

'-------------------------------------------------------------------------
' PROGRAM VARIABLES;
'-------------------------------------------------------------------------

    DIM SHARED AS INTEGER HALFX,HALFY
   
                          HALFX=XRES/2:' SIMPLE OPTIMISATIONS TO SAVE 2 DIVIDES
                          HALFY=YRES/2:' PER STAR LATER ON.

    DIM SHARED AS INTEGER STNM = 1000 :' HOW MANY STARS TO HAVE.
   
    DIM SHARED AS DOUBLE  STX(STNM):'    STORES STAR X POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STY(STNM):'    STORES STAR Y POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STZ(STNM):'    STORES STAR Z POS 3D CO-ORDINATE

'-------------------------------------------------------------------------
' SUBROUTINES;
'-------------------------------------------------------------------------

    DECLARE SUB SETUP_STARS():'          WILL SET UP INITIAL POSITIONS.
    DECLARE SUB STARFIELD():'            WILL BE USED TO DRAW THE STARS.
   
    SETUP_STARS():'                      CREATE SOME STAR POSITIONS.
   
'------------------------------------------------------------------------
' MAIN LOOP ( LOOP FOREVER :-P )
'------------------------------------------------------------------------

    WHILE(1)
       
       
        STARFIELD():'                    CALL THE STARFIELD ROUTINE.
        PTC_UPDATE@BUFFER(0):'           UPDATE THE SCREEN BUFFER.
        ERASE BUFFER:'                   CLEAR THE BUFFER AND .:. THE SCREEN.
   
   
    WEND
    END
   
'------------------------------------------------------------------------
' STARFIELD
'------------------------------------------------------------------------

SUB STARFIELD()
   
DIM AS INTEGER L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)


' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
   
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX =( STX(L)/STZ(L) ) + HALFX:' TRANSFORM 3D X TO 2D X
        TY =( STY(L)/STZ(L) ) + HALFY:' TRANSFORM 3D Y TO 2D Y
       
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
        ' AND THEN MOVE IT A LITTLE BIT CLOSER FOR NEXT TIME WE LOOK AT IT.
       
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES AND STZ(L) > 0 THEN
           
            CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
            '                               CALCULATED BY REVERSING THE SIGN OF Z
            '                               AND THEN BRINGING INTO RANGE AND FINALLY
            '                               MULTIPLYING BY 10 SO IT ENDS UP
            '                               BETWEEN 0 AND 250
           
            BUFFER (TX+(TY*XRES)) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
           
            STZ(L) = STZ(L)-.1:'                     MOVE IT IN A LITTLE
           
           
        ELSE
           
           
            ' IF THE STAR IS NOT ON THE SCREEN WE SET THE Z POS INTO
            ' THE DISTANCE AND GENERATE NEW X AND Y POSITIONS BECAUSE IT HAS GONE
            ' OUT OF VIEW.             
           
            STZ(L) =  25:'                   SET MAXIMUM DEPTH
            STX(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
            STY(L) = -5000+ (RND(1)*10000):' GENERATE NUMBER BETWEEN -5000 AND + 5000
           
           
        END IF
       
    NEXT

END SUB

'------------------------------------------------------------------------
' INITIALISE STARS
'------------------------------------------------------------------------

SUB SETUP_STARS()
    DIM L AS INTEGER :'                   LOOP COUNTER
   
    '                                     LOOP THROUGH EACH STAR IN TURN
    '                                     REMEMBER THAT STNM HOLDS THE AMOUNT OF STARS.
   
    FOR L=1 TO STNM
       
        STX(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STY(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STZ(L) = RND(1)*25:'             GENERATE AND STORE A NUMBER BETWEEN 0 AND + 25
       
    NEXT
   
END SUB

Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 12, 2007
well spotted rain!! i think you might have that right.

my code above fixes this too but i was going in a diffrent direction  :P .
Title: Re: Coding Excersise. 3D Starfields.
Post by: Shockwave on May 12, 2007
Hehe, Nino got up and down movement first, so Karma up for that, I would have done it a little differently but it works.

The way you've done it is to add offsets to the transformed co-ordinates which works, but because you are adding to integers it creates a movement that is not smooth enough for an intro. The same technique could have been applied to the original co-ordinates as long as some bounds checking was included to make the sine movement perfectly smooth, but props for being first to impliment horizontal and vertical movement!

Rain Storm, also first to rotate the stars! Well done :) an improvement I'd suggest is to calculate as much as possible before the loop, COS(ROTZ) etc always remain constant in the loop so you can get rid of a few thousand calculations by doing this before the loop! However, Karma up for that.

Also Rain Storm got the logical bug too! Theoretically if the program was run for long enough (for a few days maybe) the stars would dissappear if x and y were 0 and end up as white dots in the middle.

There is another possible bug too, there's no bounds checking for the colour brightness variable.

Still one challenge remains and that's to make them move in and out of the screen :)

I'm impressed though, you've both elegantly solved 3 of the problems between you :)
Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 13, 2007
cheers shockwave likei said its really fun to do little bit like this.

ill probably leave the last challenge for someone else to havea go  ;)

any more of these lined up?
Title: Re: Coding Excersise. 3D Starfields.
Post by: Shockwave on May 13, 2007
Probably, as soon as I can think of something. Glad you enjoyed it.
Title: Re: Coding Excersise. 3D Starfields.
Post by: Shockwave on May 13, 2007
I couldn't resist doing my own excersise :)

All bugs solved, Up / Down and Left / Right , In/ Out movements added.
Also combined with one axis of rotation to create a pleasant viewing  experience.

Code: [Select]

'
' THIS IS JUST TO SHOW HOW BEAUTIFUL THE MOVEMENT OF A 3D STAR FIELD
' CAN REALLY BE.
' HOPE YOU LIKE IT :-)
' SHOCKWAVE^S!P

'-------------------------------------------------------------------------
' CONSTANTS;
'-------------------------------------------------------------------------

    CONST   XRES    =   640:'            SCREEN WIDTH
    CONST   YRES    =   480:'            SCREEN HEIGHT

'-------------------------------------------------------------------------
' FIXED SIZE ARRAYS, DEFINE >ALL< VARIABLES;
'-------------------------------------------------------------------------

    OPTION STATIC
    OPTION EXPLICIT

'-------------------------------------------------------------------------
' INCLUDES;
'-------------------------------------------------------------------------

   ' #DEFINE PTC_WIN
    #INCLUDE ONCE  "TINYPTC.BI"

'-------------------------------------------------------------------------
' SCREEN BUFFER;
'-------------------------------------------------------------------------

    DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )

'-------------------------------------------------------------------------
' OPEN SCREEN
'-------------------------------------------------------------------------

    If( ptc_open( "AS SIMPLE AS IT GETS", XRES, YRES ) = 0 ) Then
    End -1
    End If

'-------------------------------------------------------------------------
' PROGRAM VARIABLES;
'-------------------------------------------------------------------------

    DIM SHARED AS INTEGER HALFX,HALFY
   
                          HALFX=XRES/2:' SIMPLE OPTIMISATIONS TO SAVE 2 DIVIDES
                          HALFY=YRES/2:' PER STAR LATER ON.

    DIM SHARED AS INTEGER STNM = 5000 :' HOW MANY STARS TO HAVE.
   
    DIM SHARED AS DOUBLE  STX(STNM):'    STORES STAR X POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STY(STNM):'    STORES STAR Y POS 3D CO-ORDINATE
    DIM SHARED AS DOUBLE  STZ(STNM):'    STORES STAR Z POS 3D CO-ORDINATE

    DIM SHARED AS DOUBLE SAD
   
'-------------------------------------------------------------------------
' SUBROUTINES;
'-------------------------------------------------------------------------

    DECLARE SUB SETUP_STARS():'          WILL SET UP INITIAL POSITIONS.
    DECLARE SUB STARFIELD():'            WILL BE USED TO DRAW THE STARS.
   
    SETUP_STARS():'                      CREATE SOME STAR POSITIONS.
   
'------------------------------------------------------------------------
' MAIN LOOP ( LOOP FOREVER :-P )
'------------------------------------------------------------------------

    WHILE(1)
       
       
        STARFIELD():'                    CALL THE STARFIELD ROUTINE.
        PTC_UPDATE@BUFFER(0):'           UPDATE THE SCREEN BUFFER.
        ERASE BUFFER:'                   CLEAR THE BUFFER AND .:. THE SCREEN.
   
   
    WEND
    END
   
'------------------------------------------------------------------------
' STARFIELD
'------------------------------------------------------------------------

SUB STARFIELD()
SAD = SAD+.005

DIM AS INTEGER L,TX,TY:' L IS LOOP COUNTER, TX,TY HOLD TRANSFORMED CO-ORDS
DIM AS INTEGER CV:'      HOLDS A VALUE TO CALCULATE COLOUR (BASED ON Z POS)

DIM AS DOUBLE ZADD,XADD,YADD:' USED TO PROVIDE MOVEMENT TO THE STARS.

'-------------------------------------------------------------------------------
' WE WILL ROTATE ONE AXIS OF IT BEFORE WE DO ANYTHING ELSE;
'-------------------------------------------------------------------------------

    DIM AS DOUBLE RGADD :' STORES THETA (ROTATION ANGLE)
    DIM AS DOUBLE MO1,MO2:' STORES MATRIX CONSTANTS FOR SPEED.
    DIM AS DOUBLE MMM,NNN:' STORES X+Y FOR ROTATION
    RGADD=.01*SIN(SAD):' CALCULATE THETA
   
    MO1= COS(RGADD):' GENERATE MATRIX CONSTANT 1
    MO2= SIN(RGADD):' GENERATE MATRIX CONSTANT 2

    FOR L=1 TO STNM
        '-----------------------------------------------------------------------
        ' ROTATE THE GRID
        '-----------------------------------------------------------------------
       
        NNN=STX(L)
        MMM=STY(L)
       
        STX(L) = MO1 * NNN - MO2 * MMM:' ONE AXIS OF ROTATION
        STY(L) = MO1 * MMM + MO2 * NNN:
       
        '-----------------------------------------------------------------------
        ' BOUNDS CHECKING DONE HERE TO AVOID "HOLES" IN STARFIELD
        '-----------------------------------------------------------------------
       
        IF STX(L)>5000 OR STX(L)<-5000 THEN STX(L)=-STX(L)
        IF STY(L)>5000 OR STY(L)<-5000 THEN STY(L)=-STY(L)
       
   NEXT

' PLEASE NOTE THAT THE ORIGINAL ARRAYS ARE FLOATING POINT AND THE VARS DEFINED
' ABOVE ARE INTEGERS (WHOLE NUMBERS), FRACTION PARTS OF NUMBERS ARE AUTOMATICALLY
' CHOPPED OFF BECAUSE OF THIS, THIS IS GOOD AS WE DON'T WANT THEM IN OUR
' COLOUR CALCULATIONS :-P

    'LOOP THROUGH ALL STARS.
   
    ZADD = .25*SIN(SAD)
    XADD =  40*SIN(SAD*.351)
    YADD =  40*SIN(SAD*.53)
   
   
   
   
    FOR L=1 TO STNM
       
       
        ' GENERATE 2D SCREEN CO-ORDINATE FOR STAR BY DIVIDING IT'S X
        ' AND IT'S Z POSITION BY IT'S Z POSITION, THEN ADD OFFSET TO BRING
        ' IT INTO THE CENTRE OF THE SCREEN.
       
       
        TX =( STX(L)/STZ(L) ) + HALFX:' TRANSFORM 3D X TO 2D X
        TY =( STY(L)/STZ(L) ) + HALFY:' TRANSFORM 3D Y TO 2D Y
       
       
       
        ' CHECK TO SEE IF THE STAR IS ON SCREEN.
        ' IF IT IS WE CALCULATE THE COLOUR FROM THE Z POS AND DRAW IT;
               
        IF TX>0 AND TX<XRES AND TY>0 AND TY<YRES THEN
           
            CV = (( -STZ(L) ) + 25 ) * 10:' BRIGHTNESS
            '                               CALCULATED BY REVERSING THE SIGN OF Z
            '                               AND THEN BRINGING INTO RANGE AND FINALLY
            '                               MULTIPLYING BY 10 SO IT ENDS UP
            '                               BETWEEN 0 AND 250
            if cv>255 then cv=255
            BUFFER (TX+(TY*XRES)) = RGB (CV,CV,CV):' DRAW STAR AT TX , TY
           
        END IF
       
        '-----------------------------------------------------------------------
        'THIS BIT MOVES THE STAR IN AND OUT AND DOES BOUNDS CHECKING
        '-----------------------------------------------------------------------
       
            STZ(L) = STZ(L)+ZADD:'                    Z MOVEMENT!
            IF ZADD>0 THEN
                IF STZ(L)>25 THEN STZ(L)=STZ(L)-25
            ELSE
                IF STZ(L)<0 THEN STZ(L)=STZ(L)+25
            END IF

            STX(L) = STX(L)+XADD:'                    X MOVEMENT!
            STY(L) = STY(L)+YADD:'                    Y MOVEMENT!
 
           

       
    NEXT

END SUB

'------------------------------------------------------------------------
' INITIALISE STARS
'------------------------------------------------------------------------

SUB SETUP_STARS()
    DIM L AS INTEGER :'                   LOOP COUNTER
   
    '                                     LOOP THROUGH EACH STAR IN TURN
    '                                     REMEMBER THAT STNM HOLDS THE AMOUNT OF STARS.
   
    FOR L=1 TO STNM
       
        STX(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STY(L) = -5000+ (RND(1)*10000):' GENERATE AND STORE A NUMBER BETWEEN -5000 AND + 5000
        STZ(L) = RND(1)*25:'             GENERATE AND STORE A NUMBER BETWEEN 0 AND + 25
       
    NEXT
   
END SUB
Title: Re: Coding Excersise. 3D Starfields.
Post by: ninogenio on May 13, 2007
lovely and k+ for solving the in/out  :)
Title: Re: Coding Excersise. 3D Starfields.
Post by: rain_storm on May 13, 2007
I was trying to figure that one out but I got sidetracked and ended up making a rota_zoomer instead hah this was a really fun exercise to tell you the truth. I could never do starfeilds that moved in various directions before. Now I can look at you first version and compare it to the final one and its clear how to do it  :D its sin waves all the way so simple yet when its put together it looks way better