Guys,

Although my wife is totally underwhelmed by this, here's a nice SDL demo. It needs some more work, but I won't get time to visit it again in the next week.

The backface culling isn't perfect, but you get the idea,

Cheers,

Nick

p.s. If you don't have enough memory to run this, try removing the third 'surfaces = bisect_array (surfaces)'.
###########################################################################
#                               Macros
###########################################################################

.macro swap(a,b)
        $I1000 = .a
        .a     = .b
        .b     = $I1000
.endm

.macro point_uninit(var)
        .var = new IntList
        .var = 7

        .var[6] = 0
.endm


.macro point(var, x,y,z)
        .point_uninit (.var)    

        .var[0] = .x
        .var[1] = .y
        .var[2] = .z
.endm

###########################################################################
#                            Demo Harness
###########################################################################


.sub main @MAIN

#     profile 1

     .local pmc surfaces
     surfaces = read_data ("teapot.dat")

     surfaces = bisect_array (surfaces)
     surfaces = bisect_array (surfaces)

     sdl_init()

     lock ()

     .local pmc main_screen
     main_screen = global 'main_screen'

     # Create a color to paint the new pixels
     .local pmc args
     args        = new PerlHash
     args[ 'r' ] = 255
     args[ 'g' ] =   0
     args[ 'b' ] =   0

    .local int color_type
    find_type  color_type, 'SDL::Color'

    .local pmc colour
    colour = new color_type, args

    .local int converted_colour
    converted_colour = colour.'color_for_surface' (main_screen)

    .local pmc matrix
     matrix = transformation_matrix (0.02, 0.,1.,0., -190.,-160.,0.)

     matrix_multiply_patches (matrix, surfaces, 1)

     plot_dots (surfaces, converted_colour)

     unlock ()
     update ()


     lock ()

     args[ 'r' ] =   0
     args[ 'g' ] =   0
     args[ 'b' ] = 255

    colour = new color_type, args

    converted_colour = colour.'color_for_surface' (main_screen)

     matrix = transformation_matrix (0.025, 0.,1.,0., 190.,-150.,0.)

     matrix_multiply_patches (matrix, surfaces, 2)

     plot_lines (surfaces, converted_colour, 0)

     unlock ()
     update ()

     lock ()

     surfaces = bisect_array (surfaces)

     args[ 'r' ] =   0
     args[ 'g' ] = 128
     args[ 'b' ] =   0

    colour = new color_type, args

    converted_colour = colour.'color_for_surface' (main_screen)

     matrix = transformation_matrix (0.05, 0.,1.,0., 50.,75.,0.)

     matrix_multiply_patches (matrix, surfaces, 3)

     plot_lines (surfaces, converted_colour, 1)

     unlock ()
     update ()

     sleep 10

     .local pmc app
     app = global 'app'
     app.'quit' ()

     end

.end

###########################################################################
#                            Bezier Stuff
###########################################################################

.macro bisect_line(in1,in2, out)

        tmp1 = .in1[0]
        tmp2 = .in2[0]
        tmp1 += tmp2
        tmp1 >>= 1
        .out[0] = tmp1

        tmp1 = .in1[1]
        tmp2 = .in2[1]
        tmp1 += tmp2
        tmp1 >>= 1
        .out[1] = tmp1

        tmp1 = .in1[2]
        tmp2 = .in2[2]
        tmp1 += tmp2
        tmp1 >>= 1
        .out[2] = tmp1

.endm


.macro bisect_bezier(in, out1, out2, index1, index2, index3, index4)

        b0 = .in[.index1]
        b1 = .in[.index2]
        b2 = .in[.index3]
        b3 = .in[.index4]

        .point_uninit (A)
        .point_uninit (B)
        .point_uninit (C)
        .point_uninit (D)
        .point_uninit (E)
        .point_uninit (F)

        .bisect_line (b0, b1, A)
        .bisect_line (b1, b2, B)
        .bisect_line (b2, b3, C)

        .bisect_line (A, B, D)
        .bisect_line (B, C, E)
        .bisect_line (D, E, F)

        .out1[.index1] = b0
        .out1[.index2] = A
        .out1[.index3] = D
        .out1[.index4] = F

        .out2[.index1] = F
        .out2[.index2] = E
        .out2[.index3] = C
        .out2[.index4] = b3

.endm


.sub bisect_patch
        .param pmc in
        .param pmc out1
        .param pmc out2
        .param pmc out3
        .param pmc out4

        out1 = 16
        out2 = 16
        out3 = 16
        out4 = 16

        .local pmc b0
        .local pmc b1
        .local pmc b2
        .local pmc b3

        .local int tmp1
        .local int tmp2

        .local pmc A
        .local pmc B
        .local pmc C
        .local pmc D
        .local pmc E
        .local pmc F

        .bisect_bezier (in, out1, out2, 0,   1,  2,  3)
        .bisect_bezier (in, out1, out2, 4,   5,  6,  7)
        .bisect_bezier (in, out1, out2, 8,   9, 10, 11)
        .bisect_bezier (in, out1, out2, 12, 13, 14, 15)

        .bisect_bezier (out1, out1, out3, 0, 4, 8, 12)
        .bisect_bezier (out1, out1, out3, 1, 5, 9, 13)
        .bisect_bezier (out1, out1, out3, 2, 6,10, 14)
        .bisect_bezier (out1, out1, out3, 3, 7,11, 15)

        .bisect_bezier (out2, out2, out4, 0, 4, 8, 12)
        .bisect_bezier (out2, out2, out4, 1, 5, 9, 13)
        .bisect_bezier (out2, out2, out4, 2, 6,10, 14)
        .bisect_bezier (out2, out2, out4, 3, 7,11, 15)

.end

###########################################################################

.sub bisect_array
        .param pmc array

        .local int upto
        upto = 0

        .local int array_size
        array_size = array

        .local pmc result
        result = new Array
        $I0 = 4*array_size
        result = $I0

        .local int index
        index = 0

bisect_array_loop:

        .local pmc bezier
        bezier = array[index]

        .local pmc patch1
        .local pmc patch2
        .local pmc patch3
        .local pmc patch4

        patch1 = new Array
        patch2 = new Array
        patch3 = new Array
        patch4 = new Array

        bisect_patch (bezier, patch1, patch2, patch3, patch4)

        # (Pushing to an array doesn't look like it's supported)
        result[upto] = patch1
        upto += 1

        result[upto] = patch2
        upto += 1

        result[upto] = patch3
        upto += 1

        result[upto] = patch4
        upto += 1

        index = index + 1
        if index < array_size goto bisect_array_loop

        .pcc_begin_return
        .return result
        .pcc_end_return

.end

###########################################################################
#                        Read from text file
###########################################################################

.sub read_data
     .param string filename

     # Open File
     open $P0, filename, "<"
     defined $I2, $P0
     if $I2 goto found_file
     printerr "Cannot find '"
     printerr filename
     printerr "' configuration file\n"
     end

found_file:

     # Read number section
     .local int number_count
     number_count = 0

     readline $S1, $P0
     $I10 = $S1

      .local pmc numbers
      numbers = new Array
      numbers = $I10

next_number:

     readline $S1, $P0
     $N0 = $S1
     numbers[number_count] = $N0

     number_count = number_count + 1

     if number_count < $I10 goto next_number

     # Read points section

     readline $S1, $P0
     $I10 = $S1

     .local int point_count
     point_count = 0

      .local pmc points
      points = new Array
      points = $I10

      $I5 = 0

next_point1:

     readline $S1, $P0

     $S0 = substr_r $S1, 0, 4
     $I0 = $S0
     $I3 = $I0
     $I0 = abs $I0
     $I0 = numbers[$I0]
     if $I3 >= 0 goto no_negate_0
     $I0 = -$I0
no_negate_0:

     $S0 = substr_r $S1, 5, 9
     $I1 = $S0
     $I3 = $I1
     $I1 = abs $I1
     $I1 = numbers[$I1]
     if $I3 > 0 goto no_negate_1
     $I1 = -$I1
no_negate_1:

     $S0 = substr_r $S1, 10, 14
     $I2 = $S0
     $I3 = $I2
     $I2 = abs $I2
     $I2 = numbers[$I2]
     if $I3 > 0 goto no_negate_2
     $I2 = -$I2
no_negate_2:

     .point ($P1, $I0, $I1, $I2)
     points[point_count] = $P1

     point_count = point_count + 1

     if point_count < $I10 goto next_point1

     # Read surfaces section

     readline $S1, $P0
     $I10 = $S1

     .local int surface_count
     .local int point_count

      .local pmc surfaces
      surfaces = new Array
      surfaces = $I10

     surface_count = 0

next_surface:

     .local pmc surface
     surface = new Array
     surface = 16

     point_count   = 0

next_point:

     readline $S1, $P0
     $I0 = $S1

     $P1 = points[$I0]
     surface[point_count] = $P1

     point_count = point_count + 1
     if point_count < 16 goto next_point

     surfaces[surface_count] = surface

     surface_count = surface_count + 1

     if surface_count < $I10 goto next_surface

     close $P0

     .pcc_begin_return
     .return surfaces
     .pcc_end_return
.end


###########################################################################
#                        Screen Access Stuff
###########################################################################

.sub plot_dots
        .param pmc array
        .param int converted_colour

        .local int array_size
        array_size = array

        .local int index
        index = 0 

plot_dots_loop:

        .local pmc bezier
        bezier = array[index]

        .local int index2
        index2 = 0

plot_dots_loop2:
        .local pmc point
        point = bezier[index2]

        .local int p0
        p0 = point[3]
        .local int p1
        p1 = point[4]
        .local int p2
        p2 = point[5]

        _plot_point (p0,p1,p2, converted_colour)

        index2 = index2 + 1
        if index2 < 16 goto plot_dots_loop2

        index = index + 1
        if index < array_size goto plot_dots_loop

.end


###########################################################################
#                         Line drawing code
###########################################################################

.sub line3d
        .param int x0
        .param int y0
        .param int z0
        .param int x1
        .param int y1
        .param int z1
        .param pmc callback
        .param int converted_colour

        .local int dd_x
        .local int d_x
        .local int inco_x
        .local int incb_x

        .local int dd_y
        .local int d_y
        .local int inco_y
        .local int incb_y

        .local int dd_z
        .local int d_z
        .local int inco_z
        .local int incb_z

        callback (x0, y0, z0, converted_colour)

        .local int dx
        .local int dy
        .local int dz

        dx = x1 - x0
        dy = y1 - y0
        dz = z1 - z0

        if dx != 0 goto line_continue
        if dy != 0 goto line_continue

        goto line_done

line_continue:

        $I0 = abs dx
        $I1 = abs dy

        if $I1 <= $I0 goto is_shallow

        # Steep line

        if dy >= 0 goto steep_dont_swap

        .swap (x0,x1)
        .swap (y0,y1)
        .swap (z0,z1)
        dx = -dx
        dy = -dy
        dz = -dz

steep_dont_swap:

        dd_x = 1
        d_x  = 2*dx
        d_x -= dy
        inco_x = 2*dx
        incb_x = dx-dy
        incb_x = 2*incb_x

        if dx >= 0 goto steep_dont_negate_x

        dd_x   = -dd_x
        d_x  = -2*dx
        d_x -= dy
        inco_x = -inco_x
        incb_x = dy+dx
        incb_x = -2*incb_x
        
steep_dont_negate_x:

        dd_z = 1
        d_z  = 2*dz
        d_z -= dy
        inco_z = 2*dz
        incb_z = dz-dy
        incb_z = 2*incb_z

        if dz >= 0 goto steep_dont_negate_z

        dd_z   = -dd_z
        d_z  = -2*dz
        d_z -= dy
        inco_z = -inco_z
        incb_z = dz+dy
        incb_z = -2*incb_z
        
steep_dont_negate_z:

steep_loop:

        if d_z <= 0 goto steep_d_z_gt_0

        d_z += incb_z
        z0  += dd_z

        goto steep_d_z_le_0

steep_d_z_gt_0:

        d_z += inco_z

steep_d_z_le_0:

        if d_x <= 0 goto steep_d_x_gt_0

        d_x += incb_x
        x0  += dd_x

        goto steep_d_x_le_0

steep_d_x_gt_0:

        d_x += inco_x

steep_d_x_le_0:

        y0 += 1

        callback (x0, y0, z0, converted_colour)

        if y0 < y1 goto steep_loop

        goto line_done

is_shallow:

        # Shallow line

        if dx >= 0 goto shallow_dont_swap

        .swap (x0,x1)
        .swap (y0,y1)
        .swap (z0,z1)
        dx = -dx
        dy = -dy
        dz = -dz

shallow_dont_swap:

        dd_y = 1
        d_y  = 2*dy
        d_y -= dx
        inco_y = 2*dy
        incb_y = dy-dx
        incb_y = 2*incb_y

        if dy >= 0 goto shallow_dont_negate_y

        dd_y   = -dd_y
        d_y  = -2*dy
        d_y -= dx
        inco_y = -inco_y
        incb_y = dy+dx
        incb_y = -2*incb_y
        
shallow_dont_negate_y:

        dd_z = 1
        d_z  = 2*dz
        d_z -= dx
        inco_z = 2*dz
        incb_z = dz-dx
        incb_z = 2*incb_z

        if dz >= 0 goto shallow_dont_negate_z

        dd_z   = -dd_z
        d_z  = -2*dz
        d_z -= dx
        inco_z = -inco_z
        incb_z = dz+dx
        incb_z = -2*incb_z
        
shallow_dont_negate_z:

shallow_loop:

        if d_y <= 0 goto shallow_d_y_gt_0

        d_y += incb_y
        y0  += dd_y

        goto shallow_d_y_le_0

shallow_d_y_gt_0:

        d_y += inco_y

shallow_d_y_le_0:

        if d_z <= 0 goto shallow_d_z_gt_0

        d_z += incb_z
        z0  += dd_z

        goto shallow_d_z_le_0

shallow_d_z_gt_0:

        d_z += inco_z

shallow_d_z_le_0:

        x0 += 1

        callback (x0, y0, z0, converted_colour)

        if x0 < x1 goto shallow_loop

line_done:

.end

###########################################################################

.sub plot_lines
        .param pmc array
        .param int converted_colour
        .param int cull

        .local pmc cb
        cb = new .Sub
        cb = addr _plot_point

        .local int array_size
        array_size = array

        .local int bez_index
        bez_index = 0 

plot_bezier_loop:

        .local pmc bezier
        bezier = array[bez_index]

        .local int x
        .local int y

        x = 0

plot_outer:

        y = 0

plot_inner:

        .local int index
        index = 4*x
        index = index + y

        .local int x_next_index
        .local int y_next_index
        
        x_next_index = index + 1
        y_next_index = index + 4

        $P0 = bezier[index]
        $P1 = bezier[x_next_index]
        $P2 = bezier[y_next_index]

        $I0  = $P0[3]
        $I1  = $P0[4]
        $I2  = $P0[5]

        $I3  = $P1[3]
        $I4  = $P1[4]
        $I5  = $P1[5]

        $I6  = $P2[3]
        $I7  = $P2[4]
        $I8  = $P2[5]

        # Try to do back face culling

        if cull == 0 goto dont_cull

        .local int tmp

        $I9  = $I0 - $I3
        $I10 = $I1 - $I4

        $I12 = $I0 - $I6
        $I13 = $I1 - $I7

        $I17 = $I9*$I13
        tmp  = $I10*$I12
        $I17 = $I17 - tmp

        if $I17 < 0 goto do_cull

dont_cull:

        line3d ($I0,$I1,$I2, $I3,$I4,  $I5, cb, converted_colour)
        line3d ($I0,$I1,$I2, $I6,$I7,  $I8, cb, converted_colour)

do_cull:

        y = y + 1
        if y < 3 goto plot_inner

        x = x + 1
        if x < 3 goto plot_outer

        bez_index = bez_index + 1
        if bez_index < array_size goto plot_bezier_loop

.end

###########################################################################
#                              SDL code
###########################################################################

.sub sdl_init

        # First load the necessary libraries
        load_bytecode "library/SDL/App.imc"
        load_bytecode "library/SDL/Rect.imc"
        load_bytecode "library/SDL/Color.imc"

        # Arguments for the SDL::App constructor
        .local pmc args
        args             = new PerlHash
        args[ 'height' ] = 480
        args[ 'width'  ] = 640
        args[ 'bpp'    ] =  16
        args[ 'flags'  ] =   1

        # Create an SDL::App object
        .local pmc app
        .local int app_type

        find_type app_type, 'SDL::App'
        app = new app_type, args

        store_global 'app', app 

        # Fetch the SDL::Surface representing the main window
        .local pmc main_screen
        main_screen = app.'surface'()

        store_global 'main_screen', main_screen

        args             = new PerlHash
        args[ 'height' ] = 480
        args[ 'width'  ] = 640
        args[ 'x'    ]   =   0
        args[ 'y'  ]     =   0

        # Create an SDL::Rect representing the entire main screen
        .local pmc rect
        .local int rect_type
        find_type  rect_type, 'SDL::Rect'
        rect = new rect_type, args

        store_global 'rect', rect

        .local int color_type
        find_type  color_type, 'SDL::Color'

        # Create a white color to paint the background
        args        = new PerlHash
        args[ 'r' ] = 255
        args[ 'g' ] = 255
        args[ 'b' ] = 255

        .local pmc white
        white = new color_type, args

        store_global 'white', white

        cls()
        main_screen.'update_rect'( rect )

.end

###########################################################################

.sub cls

        .local pmc main_screen
        .local pmc rect
        .local pmc white

        main_screen = global 'main_screen'
        rect = global 'rect'
        white = global 'white'

        # draw the background
        main_screen.'fill_rect'( rect, white )

.end

###########################################################################

.sub update

     .local pmc main_screen
     main_screen = global 'main_screen'

     .local pmc rect
     rect = global 'rect'
     main_screen.'update_rect'( rect )

.end


.sub lock

     .local pmc main_screen
     main_screen = global 'main_screen'

        # lock the raw framebuffer
        main_screen.'lock'()
.end

.sub unlock

     .local pmc main_screen
     main_screen = global 'main_screen'

        # lock the raw framebuffer
        main_screen.'unlock'()
.end

###########################################################################

.sub _plot_point
        .param int p0
        .param int p1
        .param int p2
        .param int converted_colour
        
        if p0 < 0    goto skip_plot
        if p0 >= 640 goto skip_plot

        if p1 < 0    goto skip_plot
        if p1 >= 480 goto skip_plot

        .local pmc main_screen
        main_screen = global 'main_screen'

        main_screen.'draw_pixel' (p0, p1, converted_colour)

skip_plot:

.end

###########################################################################
#                           Transformation
###########################################################################

.sub transformation_matrix
        .param num scale
        .param num roll
        .param num pitch
        .param num yaw
        .param num x
        .param num y
        .param num z

        .local num cosroll
        .local num sinroll
         cos cosroll, roll
         sin sinroll, roll

        .local num cospitch
        .local num sinpitch
         cos cospitch, pitch
         sin sinpitch, pitch

        .local num cosyaw
        .local num sinyaw
         cos cosyaw, yaw
         sin sinyaw, yaw

        .local num sinyawcosroll
        .local num sinyawsinroll
        sinyawcosroll = sinyaw*cosroll
        sinyawsinroll = sinyaw*sinroll

        $P0 = new Array
        $P0 = 16

        .local num tmp1
        .local num tmp2

        # Matrix row 1
        tmp1 = cosyaw*cosroll
        tmp1 = scale * tmp1
        $P0[0] = tmp1

        tmp1 = sinpitch*sinyawcosroll
        tmp2 = cospitch*sinroll
        tmp1 = tmp1 - tmp2
        tmp1 = scale * tmp1
        $P0[1] = tmp1

        tmp1 = cospitch*sinyawsinroll
        tmp2 = sinpitch*sinroll
        tmp1 = tmp1 + tmp2
        tmp1 = scale * tmp1
        $P0[2] = tmp1
        
        $P0[3] = x

        # Matrix row 2
        tmp1 = cosyaw*sinroll
        tmp1 = scale * tmp1
        $P0[4] = tmp1

        tmp1 = sinpitch*sinyawsinroll
        tmp2 = cospitch*cosroll
        tmp1 = tmp1 + tmp2
        tmp1 = scale * tmp1
        $P0[5] = tmp1

        tmp1 = cospitch*sinyawsinroll
        tmp2 = sinpitch*cosroll
        tmp1 = tmp1 - tmp2
        tmp1 = scale * tmp1
        $P0[6] = tmp1
        
        $P0[7] = y

        # Matrix row 3
        tmp1 = -sinyaw
        tmp1 = scale * tmp1
        $P0[8] = tmp1

        tmp1 = cosyaw*sinpitch
        tmp1 = scale * tmp1
        $P0[9] = tmp1

        tmp1 = cosyaw*cospitch
        tmp1 = scale * tmp1
        $P0[10] = tmp1
        
        $P0[11] = z

        # Matrix row 4
        $P0[12] = 0
        $P0[13] = 0
        $P0[14] = 0
        $P0[15] = 1

        .pcc_begin_return
        .return $P0
        .pcc_end_return

.end

.sub matrix_multiply_point

        .param pmc matrix
        .param pmc point

        # Convert the point to floats

        .local num px
        .local num py
        .local num pz

        $I0 = point[0]
        px = $I0

        $I0 = point[1]
        py = $I0

        $I0 = point[2]
        pz = $I0

        # Actually do the matrix multiplication

        .local num m00
        .local num m01
        .local num m02
        .local num x

        .local num m10
        .local num m11
        .local num m12
        .local num y

        .local num m20
        .local num m21
        .local num m22
        .local num z

        m00 = matrix[0]
        m01 = matrix[1]
        m02 = matrix[2]
        x   = matrix[3]

        m10 = matrix[4]
        m11 = matrix[5]
        m12 = matrix[6]
        y   = matrix[7]

        m20 = matrix[8]
        m21 = matrix[9]
        m22 = matrix[10]
        z   = matrix[11]

        .local num tmp1
        .local num tmp2

        tmp1 = m00 * px
        tmp2 = m01 * py
        tmp1 = tmp1 + tmp2
        tmp2 = m02 * pz
        tmp1 = tmp1 + tmp2
        tmp1 = tmp1 + x
        $I0  = tmp1
        point[3] = $I0

        tmp1 = m10 * px
        tmp2 = m11 * py
        tmp1 = tmp1 + tmp2
        tmp2 = m12 * pz
        tmp1 = tmp1 + tmp2
        tmp1 = tmp1 + y
        $I0  = tmp1
        point[4] = $I0


        tmp1 = m20 * px
        tmp2 = m21 * py
        tmp1 = tmp1 + tmp2
        tmp2 = m22 * pz
        tmp1 = tmp1 + tmp2
        tmp1 = tmp1 + z
        $I0  = tmp1
        point[5] = $I0
        
.end


.sub matrix_multiply_patches
        .param pmc matrix
        .param pmc array
        .param int generation

        .local int array_size
        array_size = array

        .local int index
        index = 0 

multiply_raw_loop:

        .local pmc bezier
        bezier = array[index]

        .local int index2
        index2 = 0

multiply_raw_loop2:
        .local pmc point
        point = bezier[index2]

        $I0 = point[6]

        # Since points are referenced by multiple patches, check if
        # this one has been transformed already
        if $I0 == generation goto skip_transform

        matrix_multiply_point (matrix, point)

        # Perform some final adhustments for screen rendering
        $I0 = point[3]
        $I1 = point[4]
        $I2 = point[5]

        # Could add some perspective here...

        # Flip y
        $I1 = -$I1

        # Place origin at canvas centre
        $I0 += 320
        $I1 += 240

        point[3] = $I0
        point[4] = $I1

        point[6] = generation

skip_transform:

        index2 = index2 + 1
        if index2 < 16 goto multiply_raw_loop2

        index = index + 1
        if index < array_size goto multiply_raw_loop

.end

Reply via email to