stick man manniquin

User projects written in or related to FreeBASIC.
Post Reply
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

stick man manniquin

Post by BasicCoder2 »

This is my stick man rigging demo.
You can select a joint by clicking on it with the mouse.
Unfortunately some joints exist at the same x,y location and the mouse can only pick one.
To compensate for this problem you can tap the space bar to move through the joints.
You can then use the left/right cursor keys to rotate the joints.

Code: Select all

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 640,480,32
'color rgb(0,0,0),rgb(255,255,255):cls

dim shared as integer selected   'selected bone number

type BONE
    as integer r       'reset start angle
    as integer p       'pointer to previous bone
    as integer x1      'absolute start
    as integer y1
    as integer x2      'end  point
    as integer y2
    as single  a       'angle of joint
    as single  aMin    'limits of joint movement
    as single  aMax
    as single  s       'size
    as ulong   c       'color
end type

dim shared as BONE bones(0 to 13)

'=================== LEG 1 ================
bones(0).x2 = 320   'start point
bones(0).y2 = 240

bones(1).r = 1

bones(1).a = 81
bones(2).a = 53
bones(3).a = 239

bones(1).s = 100
bones(2).s = 100
bones(3).s = 30

bones(1).c = rgb(255,0,0)
bones(2).c = rgb(255,0,0)
bones(3).c = rgb(255,0,0)

bones(1).p = 0
bones(2).p = 1
bones(3).p = 2

'==================== LEG 2 =====================
bones(4).r = 1

bones(4).a = 59
bones(5).a = 53
bones(6).a = 239

bones(4).s = 100
bones(5).s = 100
bones(6).s = 30

bones(4).c = rgb(0,255,0)
bones(5).c = rgb(0,255,0)
bones(6).c = rgb(0,255,0)

bones(4).p = 0
bones(5).p = 4
bones(6).p = 5

'===================== TORSO ========================

bones(7).r = 1
bones(7).a = 270
bones(7).s = 100
bones(7).c = rgb(0,0,255)
bones(7).p = 0

'===================== ARM 1 =========================

bones(8).r = 1

bones(8).a = 81
bones(9).a = 294
bones(10).a = 315

bones(8).s = 80
bones(9).s = 70
bones(10).s = 30

bones(8).c = rgb(0,255,255)
bones(9).c = rgb(0,255,255)
bones(10).c = rgb(0,255,255)

bones(8).p = 7
bones(9).p = 8
bones(10).p = 9

'===================== ARM 2 =========================

bones(11).r = 1

bones(11).a = 114
bones(12).a = 343
bones(13).a = 239

bones(11).s = 80
bones(12).s = 70
bones(13).s = 30

bones(11).c = rgb(155,155,0)
bones(12).c = rgb(155,155,0)
bones(13).c = rgb(155,155,0)

bones(11).p = 7
bones(12).p = 11
bones(13).p = 12


dim shared as single angle

sub drawBones()
    screenlock
    cls
    angle = 0
    locate 2,1
    for i as integer = 1 to 13
        color bones(i).c
        if bones(i).r = 1 then angle = 0:print
        if bones(i).a < 0   then bones(i).a = bones(i).a + 360
        if bones(i).a > 359 then bones(i).a = bones(i).a - 360
        angle = angle + bones(i).a
        if angle < 0   then angle = angle + 360
        if angle > 359 then angle = angle - 360
        bones(i).x1 = bones( bones(i).p ).x2
        bones(i).y1 = bones( bones(i).p ).y2
        bones(i).x2 = bones(i).x1 + cos(angle*DtoR) * bones(i).s
        bones(i).y2 = bones(i).y1 + sin(angle*DtoR) * bones(i).s  
        line (bones(i).x1,bones(i).y1)-(bones(i).x2,bones(i).y2),bones(i).c
        circle (bones(i).x1,bones(i).y1),3,rgb(200,200,200)
        if selected = i then
            circle (bones(i).x1,bones(i).y1),5
            draw string (bones(i).x1+8,bones(i).y1), str(selected)
        end if
        print i;" ";bones(i).a,angle
    next i
    screenunlock
end sub

dim as string key
dim as integer mx,my,mb

drawBones()
dim as single dd,dx,dy
do

        getmouse mx,my,,mb
        if mb = 1 then
            for i as integer = 0 to 13
                dx = mx-bones(i).x1
                dy = my-bones(i).y1
                dd = sqr(dx^2+dy^2)
                if dd < 5 then
                    selected = i
                end if
            next i
        end if
        
        key = inkey
        If key=Chr(255) +"K" Then bones(selected).a = bones(selected).a - 1
        If key=Chr(255) +"M" Then bones(selected).a = bones(selected).a + 1
        if key = " " then selected = selected + 1
        if selected = 14 then selected = 1
        drawBones()
    
    sleep 2
loop until  multikey(&H01)
 
sleep

If the joints could be positioned in a 3D volume instead of being restricted to 2D surface with the ability to rotate them around the center of the figure you could probably use the mouse to select all the joints.

It might look something like this.

Code: Select all

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 940,480,32

sub setXYZ(x as double,y as double,z as double)
    circle (x+z\2,y-z\2),3,rgb(0,255,0)
    'draw string (x+z\2,y-z\2),str(int(x+.5))+","+str(int(y+.5))+","+str(int(z+.5))
end sub

sub lineXYZ(x1 as double,y1 as double,z1 as double,x2 as double,y2 as double,z2 as double)
    line (x1+z1\2,y1-z1\2)-(x2+z2\2,y2-z2\2),rgb(255,0,0)
    setXYZ(x1,y1,z1)
    setXYZ(x2,y2,z2)
end sub

type ALINE
    as integer x1
    as integer y1
    as integer z1
    as integer x2
    as integer y2
    as integer z2
end type

dim shared as ALINE lines(1 to 15)

dim shared as integer x1,y1,z1,x2,y2,z2
for i as integer = 1 to 15   'draw 15 lines
    read lines(i).x1,lines(i).y1,lines(i).z1,lines(i).x2,lines(i).y2,lines(i).z2
    lineXYZ(x1,y1,z1,x2,y2,z2)
next i

sub drawLines()
    screenlock
    cls
    for i as integer = 1 to 15   'draw 15 lines
        lineXYZ(lines(i).x1,lines(i).y1,lines(i).z1,lines(i).x2,lines(i).y2,lines(i).z2)
    next i
    screenunlock
end sub

sub rotatePointsY()
    dim as double px1,py1,pz1,px2,py2,pz2,rx1,ry1,rz1,rx2,ry2,rz2
    for angle as double = 0 to 360
        cls
        for i as integer = 1 to 15  '15 lines
            pz1 = lines(i).z1 - 50
            px1 = lines(i).x1 - 350
            py1 = lines(i).y1 - 350 
            rz1 = (Cos(angle*DtoR) * pz1 - Sin(angle*DtoR) * px1)+50
            rx1 = (Sin(angle*DtoR) * pz1 + Cos(angle*DtoR) * px1)+350
            ry1 = py1+340
            pz2 = lines(i).z2 - 50
            px2 = lines(i).x2 - 350
            py2 = lines(i).y2 - 350 
            rz2 = (Cos(angle*DtoR) * pz2 - Sin(angle*DtoR) * px2)+50
            rx2 = (Sin(angle*DtoR) * pz2 + Cos(angle*DtoR) * px2)+350
            ry2 = py2+340
            LINEXYZ(rx1,ry1,rz1,rx2,ry2,rz2)
        next i
        sleep 50
    next angle
end sub

rotatePointsY()

'drawLines()


sleep


data 321,140,-20,321,140,+20  'shoulder

data 321,140,-20,288,213,-20  'left arm top
data 288,213,-20,280,280,-20  'lower
data 280,280,-20,306,270,-20  'wrist

data 321,140,+20, 334,218,+20 'right arm
data 334,218,+20, 402,237,+20
data 402,237,+20, 428,222,+20

data 322,239,-20, 322,239,+20 'hip

data 322,239,-20, 338,338,-20  'left leg
data 338,338,-20, 268,411,-20
data 268,411,-20, 297,419,-20

data 322,239,+20, 373,326,+20
data 373,326,+20, 337,419,+20
data 337,419,+20, 367,414,+20

data 321,140,0, 322,239,0    'torso


leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: stick man manniquin

Post by leopardpm »

LOL! luv it... nice little demo
Pitto
Posts: 122
Joined: Nov 19, 2012 19:58

Re: stick man manniquin

Post by Pitto »

Hi BasicCoder2,

well done demo. I like it.

I think that, adding the possibility to record each node position along a timeline, an interesting animation could be created.
Looks like a technique used a long time ago to render graphics in a videogame of the early 90's called "another World": https://www.anotherworld.fr/anotherworl ... sation.htm
It would be nice to be able to manage some connected polygons with each other in a hierarchical way.
Maybe I went a bit 'off topic :)
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: stick man manniquin

Post by BasicCoder2 »

Pitto wrote:Hi BasicCoder2,
well done demo. I like it.
Thanks for the feedback.

May I say that I admired your programming of a soccer game something I wasn't able to complete.
I think that, adding the possibility to record each node position along a timeline, an interesting animation could be created.
That was the idea. You move the bones and save the the positions. Later you can play back the positions and have an animation as they do in the 3D Blender software. Elsewhere I have covered the bones with a polygon so for example the torso would be one line (the backbone) but it would orientate a square polygon (or any shape polygon for that matter). I did this somewhere in a robot arm demo. It all takes time to write and debug this stuff and for that you need motivation. It is really only reinventing what professionals have already done better. My weakness is not having a grasp of 3D math.
It would be nice to be able to manage some connected polygons with each other in a hierarchical way.
Maybe I went a bit 'off topic :)
The only reason for keeping on topic is when searching for a subject. There is some good stuff in the squares thread but unless you happen to hit on the right key words in the search facility you will not find them. None of this stuff is going anywhere in a commercial sense. It is all just playing about with code as someone might play around with a puzzle game.

It is easy enough to make many polygons and they will stay together over rotation and magnification. I have messed with that somewhere but it all 2D stuff.

Here is the logic used in the polygon drawing mode in one of my vector paint programs.

You draw a polygon with the mouse. Move the mouse while holding down the left button and a line will be drawn between the start point and the current point. Repeat and the lines will all join. End it by ending a line at the start point. A dotted rectangle will then enclose the polygon. By holding the button down within that rectangle you can move the polygon where ever you like. Click outside the rectangle to end it. The polygons are saved in an array and in other code examples you could step through the polygons to delete or edit them later.

Code: Select all

const wCanvas = 640
const hCanvas = 480
const SCRW = 840
const SCRH = 552
const POSX = 180
const POSY = 60

screenres SCRW,SCRH,32

color rgb(1,1,1),rgb(254,254,254)  'black ink, white paper
cls 'executes color statement settings

dim shared as integer mx,my,mb,ox,oy,sx,sy,x1,y1,x2,y2,dx,dy

dim shared as any ptr canvas3,canvas2,canvas1
canvas3 = imagecreate(wCanvas,hCanvas,rgb(255,  0,255)) 'current shape drawn here
canvas2 = imagecreate(wCanvas,hCanvas,rgb(255,254,255)) 'save current picture
canvas1 = imageCreate(wCanvas,hCanvas,rgb(255,254,255)) 'current screen to display

type SHAPE
    as integer  x(100)  'absolute coordinates of points on screen
    as integer  y(100)
    as integer  size    'number of coordinates
    as uinteger c1      'boundary color
    as uinteger c2      'fill color
end type

dim shared as SHAPE shapes(100)  'up to 100 shapes
dim shared as integer sCount     'actual number of shapes

'===============================================
'DRAWS CURRENT LINES FOR SHAPE USED BY getShape()
'===============================================
sub drawShape(s as SHAPE)
    line canvas3,(0,0)-(wCanvas-1,hCanvas-1),rgb(255,0,255),bf  'clear drawing buffer
    if s.size<>0 then
        for i as integer = 0 to s.size-2
            line canvas3,(s.x(i),s.y(i))-(s.x(i+1),s.y(i+1)),rgb(0,0,0)
        next i
    end if
end sub

sub update()
    screenlock()
    cls
    'draw shapes
    'copy to display
    put (POSX,POSY),canvas1,pset
    'draw screen box
    line (POSX-2,POSY-2)-(POSX+wCanvas+2,POSY+hCanvas+2),rgb(1,1,1),b
    line (POSX-4,POSY-4)-(POSX+wCanvas+4,POSY+hCanvas+4),rgb(1,1,1),b
    locate 1,1
    print "NUMBER OF SHAPES: ";sCount
    screenunlock()
end sub

'==================================================
'ALLOWS USER TO DRAW A SHAPE OUT OF CONNECTED LINES
'EXITS SHAPE DRAWING WHEN START OF FIRST LINE IS
'CONNECTED BY END OF LAST LINE. IT THEN ALLOW THE
'USER TO MOVE AND RESIZE THE SHAPE.
'==================================================
function getShape() as SHAPE
    dim s as SHAPE
    s.c1 = rgb(0,0,0)
    s.c2 = rgb(200,200,200)
    
    s.size = 0  'clear list
    
    'get first coordinate
    
    'save current screen
    get (POSX,POSY)-(POSX+wCanvas-1,POSY+hCanvas-1),canvas2
    'clear canvas3 with magenta
    line canvas3,(0,0)-(wCanvas-1,hCanvas-1),rgb(255,0,255),bf

    sx = mx
    sy = my
    s.x(s.size)=mx-POSX  'save first coordinate
    s.y(s.size)=my-POSY
    s.size = s.size + 1

    'get next coordinate
    do
        'wait for button down
        getmouse mx,my,,mb
        while mb<>1
            getmouse mx,my,,mb
        wend
        ox = mx
        oy = my
        line canvas3,(sx-POSX,sy-POSY)-(mx-POSX,my-POSY),s.c1 'draw current line being drawn
        'erase current screen drawing with previous saved screen
        put canvas1,(0,0),canvas2,pset
        'copy latest drawing stage onto display canvas
        put canvas1,(0,0),canvas3,trans
        update()
        do
            getmouse mx,my,,mb
            if mx<>ox or my<>oy then 'it has moved
                drawShape(s)
                line canvas3,(sx-POSX,sy-POSY)-(mx-POSX,my-POSY),s.c1 'draw current line being drawn
                'erase current screen drawing with previous saved screen
                put canvas1,(0,0),canvas2,pset
                'copy latest drawing stage onto screen
                put canvas1,(0,0),canvas3,trans
                update()
                ox = mx
                oy = my
            end if
            sleep 1
        loop until mb<>1
        
        'save next coordinate
        s.x(s.size)=mx-POSX
        s.y(s.size)=my-POSY
        s.size = s.size + 1
        sx = mx  'start of next line
        sy = my
        

        'loop until close to start
    loop until sx-POSX>s.x(0)-3 and sx-POSX<s.x(0)+3 and sy-POSY>s.y(0)-3 and sy-POSY<s.y(0)+3
    s.x(s.size-1)=s.x(0)  'make last coordinate start coordinate
    s.y(s.size-1)=s.y(0)

    'find dimensions of box around shape
    dim as integer x1,x2,y1,y2 
    x1 = 1000
    y1 = 1000
    x2 = 0
    y2 = 0

    'get dimensions of box around shape
    for i as integer = 0 to s.size-1
        if s.x(i)<x1 then x1 = s.x(i)
        if s.x(i)>x2 then x2 = s.x(i)
        if s.y(i)<y1 then y1 = s.y(i)
        if s.y(i)>y2 then y2 = s.y(i)
    next i

    drawShape(s)
    'draw dotted box around shape
    line canvas3,(x1,y1)-(x2,y2),rgb(1,1,1),b,&b1111000011110000
    'draw resize tag on bottom/right corner of box
    line canvas3,(x2,y2)-(x2+5,y2+5),rgb(1,1,1),b
    'erase current screen drawing with previous saved screen
    put canvas1,(0,0),canvas2,pset
    'copy latest drawing stage onto screen
    put canvas1,(0,0),canvas3,trans
    update()

'=================================================================
'  MOVES OR RESIZES SHAPE UNTIL BUTTON DOWN ELSEWHERE
'=================================================================
    dim as integer dx,dy
    do
        getmouse mx,my,,mb
            ox = mx
            oy = my
        
        'MOVE SHAPE WHILE BUTTON DOWN INSIDE BOX
        if mb=1 and mx>x1+POSX and mx<x2+POSX and my>y1+POSY and my<y2+POSY then  'inside box
            while mb=1  'while button held down
                getmouse mx,my,,mb
                if mx<>ox or my<>oy then 'mouse has moved
                    dx = mx-ox
                    dy = my-oy   'amount it has moved
                
                    'update coordinates positions
                    for i as integer = 0 to s.size-1
                        s.x(i)=s.x(i)+dx
                        s.y(i)=s.y(i)+dy
                    next i
                    
                    x1 = x1 + dx
                    x2 = x2 + dx
                    y1 = y1 + dy
                    y2 = y2 + dy
                
                    drawShape(s)
                    line canvas3,(x1,y1)-(x2,y2),rgb(1,1,1),b,&b1111000011110000
                    line canvas3,(x2,y2)-(x2+6,y2+6),rgb(1,1,1),b
                    'erase current screen drawing with previous saved screen
                    put canvas1,(0,0),canvas2,pset
                    'copy latest drawing stage onto screen
                    put canvas1,(0,0),canvas3,trans
                    update()
                    'line canvas3,(x1,y1)-(x2,y2),rgb(1,1,1),b,&b1111000011110000
                    'line canvas3,(x2,y2)-(x2+5,y2+5),rgb(1,1,1),b  
                    ox = mx
                    oy = my
                end if
            wend
        end if

        'RESIZE SHAPE WHILE BUTTON DOWN WITHIN TAG AREA
        dim as double LX,LY,r1,r2
        if mb=1 and mx>x2+POSX and my>y2+POSY and mx<x2+6+POSX and my<y2+6+POSY then
        'if mb=1 and mx>x2-5 and my>y2-5 and mx<x2+5 and my<y2+5 then
            while mb=1
                getmouse mx,my,,mb
                if mx<>ox or my<>oy then  'mouse has moved
                    dx = mx-ox
                    dy = my-oy   'amount it has moved
                    LX = (x2 + dx)-x1  'new width and height of box
                    LY = (y2 + dy)-y1
                    for i as integer = 0 to s.size-1
                        r1 = (s.x(i)-x1)/(x2-x1)
                        r2 = (s.y(i)-y1)/(y2-y1)
                        s.x(i)=LX*r1+x1
                        s.y(i)=LY*r2+y1
                    next i
                    x2 = x2 + dx
                    y2 = y2 + dy                
                    drawShape(s)
                    line canvas3,(x1,y1)-(x2,y2),rgb(1,1,1),b,&b1111000011110000
                    line canvas3,(x2,y2)-(x2+6,y2+6),rgb(1,1,1),b
                    'erase current screen drawing with previous saved screen
                    put canvas1,(0,0),canvas2,pset
                    'copy latest drawing stage onto screen
                    put canvas1,(0,0),canvas3,trans
                    update()
                    'line canvas3,(x1,y1)-(x2,y2),rgb(1,1,1),b,&b1111000011110000
                    'line canvas3,(x2,y2)-(x2+5,y2+5),rgb(1,1,1),b
                    ox = mx
                    oy = my
                end if
            wend
        end if
    
    loop until mb=1 and (mx<x1 or mx>x2 or my<y1 or my>y2)
    
'=========================================================
'           FILLS IN SHAPE WITH COLOR2
'=========================================================

    'fill in shape
    drawShape(s)  'clears canvas3 and draws shape s
    'fill outside of shape with white
    paint canvas3,(0,0),rgb(254,254,254),s.c1

    'fill any magenta area which will be inside shape with color2
    for j as integer = 0 to hCanvas-1
        for i as integer = 0 to wCanvas-1
            if point(i,j,canvas3)=rgb(255,0,255) then
                pset canvas3,(i,j),s.c2
            end if
        next i
    next j
    
    'refill outside of shape with magenta
    paint canvas3,(0,0),rgb(255,0,255),s.c1
    'erase current screen drawing with previous saved screen
    put canvas1,(0,0),canvas2,pset
    'copy latest drawing stage onto screen
    put canvas1,(0,0),canvas3,trans
    update()  'copy shape onto screen
    while mb=1
        getmouse mx,my,,mb
    wend
    return s
end function


' ====  MAIN PROGRAM ====

update()

do
    getmouse mx,my,,mb
    'is it over drawing area??
    if mb = 1 and mx > POSX and mx < POSX+wCanvas and my>POSY and my<POSY+hCanvas then
        shapes(sCount) = getShape()
        sCount = sCount + 1
    end if    
    update()
    sleep 1
loop until multikey(&H01)

'draw shapes
cls
if sCount<>0 then
    for i as integer = 0 to sCount-1

    if shapes(i).size<>0 then
        for j as integer = 0 to shapes(i).size-2
            line (shapes(i).x(j),shapes(i).y(j))-(shapes(i).x(j+1),shapes(i).y(j+1)),rgb(0,0,0)
        next j
    end if

    next i
end if

dim as string key
key = inkey
while key<>"x"
    key = inkey
wend

imageDestroy(canvas1)
imageDestroy(canvas2)
imageDestroy(canvas3)
Last edited by BasicCoder2 on Sep 16, 2017 23:10, edited 1 time in total.
Pitto
Posts: 122
Joined: Nov 19, 2012 19:58

Re: stick man manniquin

Post by Pitto »

Hi BasicCoder2,

for me too programming is a fun passtime, but often I notice that some things I've learned programming may be applied to other fields.

Coming back to topic, would be cool having the ability to set up key-frames and the program could interpolate frames in between. First time I've seen this many years ago in a commercial vector software I was left speechless.

Reinventing what professionals have already done is a fun process too. And if anyone releases his source, others may have inspiration for inventing something new. For example, I've examined the code snipped above (nice it too), I'd use the fill routine that you used in mine FBB project - thanks for sharing.

P.S. Jasc Soccer is in stand-by at moment, but I would like to continue to develop it.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: stick man manniquin

Post by BasicCoder2 »

Pitto wrote:Coming back to topic, would be cool having the ability to set up key-frames and the program could interpolate frames in between. First time I've seen this many years ago in a commercial vector software I was left speechless..
Between each frame each joint would have change by some amount so to insert intermediate frames perhaps just divide the changes of each joint by the number of frames to be inserted plus one to get the incremental values to add to the first set of joint positions?

Thus if a joint changed from 60 to 70 then the change was +10. So lets say one intermediate frame was to be inserted then the joint position for that frame would be 60 + 5.

The other change not implemented above would be the movement of the reference point which in the example is at the hip. This reference point could also be moved automatically if say the feet are not touching the ground (or are below ground).

The same logic could also be applied to intermediate rotations and magnifications.

Now if three frames are considered and you want intermediate values it might be like using the Bezier curve to generate the intermediate positions.

Or just learn to use the software that already does all this including software that deals with 3D objects and their physics :)
.
leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: stick man manniquin

Post by leopardpm »

your keyframe interpolation is spot on, and the addition of bezier curves upon which to interpolate is good too.

I do hate (and love) reinventing the wheel - it does provide satisfaction. Remember we do this to improve our own knowledge, not exactly to make the world a better place... to do that you need to improve upon it or come up with a completely different approach or result. And to do that, it helps to understand the initial algorithm thoroughly, which is what we are doing... so, in the end, its all positives any way you cut it!
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: stick man manniquin

Post by BasicCoder2 »

This is just to see if it piques anyone's interest. It seemed to me that you could write a rigging editor with FreeBasic and then flesh it out with the pixel cloud as seen in dodicat's demos. I dabbled with a simple stick figure and then thought about giving it an isometric display as shown above.

The example below is supposed to be a walking bear (headless at this stage). It was edited by a simple rigging editor I have been trying to develop. The output of the editor is in the data statements. The editor can change the angle of a pivot point and/or the length of a bone being rotated.

Be it a bear or a man the bones are the same, they just vary in length. I changed the angle and length of a stickman bone set to make a bear bone set. Different actions are simply sequences of angles over units of time. It is no different to controlling a robot man or bear (or dog) except it is virtual not an actual physical entity.

For reasons I don't understand such sequences and bone lengths are not shared or available for those making 3d animations using rendering software. Such sequences would best be extracted from the actions of real animals rather than the silly manual positioning of bones for each frame as appears to be the case in the current batch of 3d rendering software.

In the simple case of the isometric 3d stick man above I just shifted the shoulder and hip positions for opposing limbs. In the example below I simply shifted the frames by 180 degrees for the other set of legs.

Code: Select all

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 800,480,32

Sub drawLine(x1 as integer,y1 as integer,x2 as integer, y2 as integer,size as integer,c as uinteger)
    Dim As Integer ax, ay, d, dxx, dyy, x, y
    circle (x1,y1),size,c,,,,f
    If x1 = x2 And y1 = y2 Then Exit Sub
  
    If x1 = x2 Then
        x = x1
        if y2>y1 then
            For y as integer  = y1 To y2
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
            Next y
        else
            for y as integer = y2 to y1
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
            next y
        end if
      
    Elseif y1 = y2 Then
        y = y1
        if x2>x1 then
            For x as integer = x1 To x2
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
            next x
        else
            for x as integer = x2 to x1
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
            next x
        end if

    Else
        dxx = x2 - x1
        dyy = y2 - y1
        ax = 1
        ay = 1
    
        If dxx < 0 Then
            dxx = -dxx
            ax = -1
        End If
    
        If dyy < 0 Then
            dyy = -dyy
            ay = -1
        End If
    
        x = x1
        y = y1
    
        dim as integer ii
    
        If dxx >= dyy Then
            ii = dxx + 1
            dyy Shl= 1
            d = dyy - dxx
            dxx Shl= 1
      
            While ii > 0
                ii -= 1
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
        
                If d >= 0 Then
                    y += ay
                    d -= dxx
                 End If
        
                 d += dyy
                 x += ax
              Wend
          Else
              ii = dyy + 1
              dxx Shl= 1
              d = dxx - dyy
              dyy Shl= 1
              While ii > 0
                  ii -= 1
                if size = 0 then
                    pset (x,y),c
                else
                    circle (x,y),size,c,,,,f
                end if
        
                  If d >= 0 Then
                      x += ax
                      d -= dyy
                  End If
        
                  d += dxx
                  y += ay
              Wend
          End If
    End If
End Sub

type PIVOT
    as integer r       'reset start angle
    as integer p       'pointer to previous bone
    as integer x1      'absolute start
    as integer y1
    as integer x2      'end  point
    as integer y2
    as single  a       'angle of joint
    as single  aMin    'limits of joint movement
    as single  aMax
    as single  s       'size
    as ulong   c       'color
end type


dim shared as single angle
'dim shared as integer selected   'selected bone number
dim shared as integer selFrame   'currently selected frame
selFrame = 1
dim shared as integer selFrame2   '
selFrame2 = 5   '180 degrees out of phase

dim shared as integer TBONES
TBONES = 8
dim shared as integer TFRAMES
TFRAMES = 8

dim shared as PIVOT pivots(1 to TFRAMES,0 to TBONES)
'set starting positions
for i as integer = 1 to TFRAMES
    pivots(i,0).x2 = 101   'start point
    pivots(i,0).y2 = 102

    pivots(i,1).r = 1

    pivots(i,1).p = 0
    pivots(i,2).p = 1
    pivots(i,3).p = 2
    pivots(i,4).p = 3

'=======================================

    pivots(i,5).r = 1
    
    pivots(i,5).p = 0
    pivots(i,6).p = 5
    pivots(i,7).p = 6
    pivots(i,8).p = 7
next i

for i as integer = 1 to TFRAMES
    for j as integer = 0 to TBONES
        read pivots(i,j).r,pivots(i,j).a,pivots(i,j).s,pivots(i,j).p
    next j
next i

sub drawBones()
    screenlock
    cls
    angle = 0
    for i as integer = 0 to TBONES
        color pivots(selFrame,i).c
        if pivots(selFrame,i).r = 1 then angle = pivots(selFrame,0).a
        if pivots(selFrame,i).a < 0   then pivots(selFrame,i).a = pivots(selFrame,i).a + 360
        if pivots(selFrame,i).a > 359 then pivots(selFrame,i).a = pivots(selFrame,i).a - 360
        angle = angle + pivots(selFrame,i).a
        if angle < 0   then angle = angle + 360
        if angle > 359 then angle = angle - 360
        pivots(selFrame,i).x1 = pivots(selFrame, pivots(selFrame,i).p ).x2
        pivots(selFrame,i).y1 = pivots(selFrame, pivots(selFrame,i).p ).y2
        pivots(selFrame,i).x2 = pivots(selFrame,i).x1 + cos(angle*DtoR) * pivots(selFrame,i).s
        pivots(selFrame,i).y2 = pivots(selFrame,i).y1 + sin(angle*DtoR) * pivots(selFrame,i).s 
        drawLine ( pivots(selFrame,i).x1, pivots(selFrame,i).y1, pivots(selFrame,i).x2, pivots(selFrame,i).y2, 3 ,rgb(255,255,0))
        if i = 1 or i = 5 then
            drawLine ( pivots(selFrame,i).x1, pivots(selFrame,i).y1, pivots(selFrame,i).x2, pivots(selFrame,i).y2, 9 ,rgb(100,100,255))
        end if
        circle (pivots(selFrame,i).x1,pivots(selFrame,i).y1),3,rgb(200,200,200)
        circle (pivots(selFrame,i).x2,pivots(selFrame,i).y2),3,rgb(200,100,0)
    next i
    
'=================================================================================
    for i as integer = 0 to TBONES
        color pivots(selFrame2,i).c
        if pivots(selFrame2,i).r = 1 then angle = pivots(selFrame2,0).a
        if pivots(selFrame2,i).a < 0   then pivots(selFrame2,i).a = pivots(selFrame2,i).a + 360
        if pivots(selFrame2,i).a > 359 then pivots(selFrame2,i).a = pivots(selFrame2,i).a - 360
        angle = angle + pivots(selFrame2,i).a
        if angle < 0   then angle = angle + 360
        if angle > 359 then angle = angle - 360
        pivots(selFrame2,i).x1 = pivots(selFrame2, pivots(selFrame2,i).p ).x2
        pivots(selFrame2,i).y1 = pivots(selFrame2, pivots(selFrame2,i).p ).y2
        pivots(selFrame2,i).x2 = pivots(selFrame2,i).x1 + cos(angle*DtoR) * pivots(selFrame2,i).s
        pivots(selFrame2,i).y2 = pivots(selFrame2,i).y1 + sin(angle*DtoR) * pivots(selFrame2,i).s 
        drawLine ( pivots(selFrame2,i).x1, pivots(selFrame2,i).y1, pivots(selFrame2,i).x2, pivots(selFrame2,i).y2, 3 ,rgb(255,0,0))
        if i = 1 or i = 5 then
            drawLine ( pivots(selFrame,i).x1, pivots(selFrame,i).y1, pivots(selFrame,i).x2, pivots(selFrame,i).y2, 9 ,rgb(100,100,255))
        end if
        circle (pivots(selFrame2,i).x1,pivots(selFrame2,i).y1),3,rgb(200,200,200)
        circle (pivots(selFrame2,i).x2,pivots(selFrame2,i).y2),3,rgb(200,100,0)
    next i
'==================================================================================

    line (0,182)-(799,182),rgb(200,100,0)
    screenunlock
end sub

dim as string key
dim as integer mx,my,mb

drawBones()

dim as single dd,dx,dy

do
    selFrame = selFrame + 1
    if selFrame > 8 then selFrame = 1
    selFrame2 = selFrame2 + 1
    if selFrame2 > 8 then selFrame2 = 1
    drawBones()

    sleep 200
loop until  multikey(&H01)

DATA  0,0,0,0,1,356,48,0,0,94,44,1,0,329,40,2,0,302,18,3,1,180,48,0,0,266,40,5,0,0,36,6,0,275,22,7
DATA  0,0,0,0,1,356,48,0,0,110,44,1,0,314,40,2,0,304,18,3,1,180,48,0,0,263,40,5,0,20,36,6,0,262,22,7
DATA  0,0,0,0,1,0,48,0,0,118,44,1,0,314,40,2,0,289,18,3,1,180,48,0,0,265,40,5,0,27,36,6,0,259,22,7
DATA  0,0,0,0,1,0,48,0,0,126,44,1,0,317,40,2,0,278,18,3,1,180,48,0,0,287,40,5,0,22,36,6,0,261,22,7
DATA  0,0,0,0,1,8,48,0,0,130,44,1,0,299,40,2,0,284,22,3,1,180,48,0,0,262,40,5,0,51,36,6,0,243,22,7
DATA  0,0,0,0,1,0,48,0,0,143,44,1,0,275,40,2,0,80,18,3,1,180,48,0,0,252,40,5,0,0,36,6,0,281,22,7
DATA  0,0,0,0,1,0,48,0,0,114,44,1,0,270,40,2,0,80,18,3,1,177,48,0,0,250,40,5,0,3,36,6,0,289,22,7
DATA  0,0,0,0,1,0,48,0,0,94,44,1,0,304,40,2,0,346,18,3,1,180,48,0,0,258,40,5,0,0,36,6,0,283,22,7


leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: stick man manniquin

Post by leopardpm »

thats really cool, BC!
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: stick man manniquin

Post by BasicCoder2 »

Now the pivot points have to be given a 3d coordinate and drawn on a isometric display.
This program rotates the animated rigging around the starting point on the "backbone".
The opposite side in the same frame are again drawn 180 degrees out of phase to the other side.
Each side is shifted in opposite directions on the z axis.
Keep in mind the z axis moves into the screen not vertically.

The reason I did not use the thick lines this time is because as the rigging rotates the order in which the parts are to be drawn changes.
To overcome this I have to replace the lines with a cloud of pixel values which can be sorted using the painter's algorithm.
.

Code: Select all

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 640,480,32

type PIVOT
    as integer r       'reset start angle
    as integer p       'pointer to previous bone
    as single x1      'absolute start
    as single y1
    as single z1
    as single x2      'end  point
    as single y2
    as single z2
    as single  a       'angle of joint in xy axis
    as single  aMin    'limits of joint movement
    as single  aMax
    as single  s       'size
    as ulong   c       'color
end type

sub setXYZ(x as single,y as single,z as single)
    circle (x+z\2,y-z\2),3,rgb(0,255,0)
end sub

sub lineXYZ(x1 as single,y1 as single,z1 as single,x2 as single,y2 as single,z2 as single)
    line (x1+z1\2,y1-z1\2)-(x2+z2\2,y2-z2\2),rgb(255,0,0)
    setXYZ(x1,y1,z1)
    setXYZ(x2,y2,z2)
end sub

dim shared as single angle,angle2

'dim shared as integer selected   'selected bone number
dim shared as integer selFrame   'currently selected frame
selFrame = 1
dim shared as integer selFrame2   '
selFrame2 = 5   '180 degrees out of phase

dim shared as integer TBONES
TBONES = 8
dim shared as integer TFRAMES
TFRAMES = 8

dim shared as PIVOT pivots(1 to TFRAMES,0 to TBONES)
'set starting positions
for i as integer = 1 to TFRAMES
    pivots(i,0).x2 = 0  'start point at 0,0,0
    pivots(i,0).y2 = 0
    pivots(i,0).z2 = 0

    pivots(i,1).r = 1

    pivots(i,1).p = 0
    pivots(i,2).p = 1
    pivots(i,3).p = 2
    pivots(i,4).p = 3

'=======================================

    pivots(i,5).r = 1
    
    pivots(i,5).p = 0
    pivots(i,6).p = 5
    pivots(i,7).p = 6
    pivots(i,8).p = 7
next i

for i as integer = 1 to TFRAMES
    for j as integer = 0 to TBONES
        read pivots(i,j).r,pivots(i,j).a,pivots(i,j).s,pivots(i,j).p
    next j
next i



sub drawBones()
    dim as single px1,py1,pz1,px2,py2,pz2,rx1,ry1,rz1,rx2,ry2,rz2
    angle2 = angle2 - 5
    screenlock
    cls
    line (320,0)-(320,479),rgb(200,200,255)
    line (0,240)-(639,240),rgb(200,200,255)
    for i as integer = 0 to TBONES
        color pivots(selFrame,i).c
        if pivots(selFrame,i).r = 1 then angle = pivots(selFrame,0).a
        if pivots(selFrame,i).a < 0   then pivots(selFrame,i).a = pivots(selFrame,i).a + 360
        if pivots(selFrame,i).a > 359 then pivots(selFrame,i).a = pivots(selFrame,i).a - 360
        angle = angle + pivots(selFrame,i).a
        if angle < 0   then angle = angle + 360
        if angle > 359 then angle = angle - 360
        pivots(selFrame,i).x1 = pivots(selFrame, pivots(selFrame,i).p ).x2
        pivots(selFrame,i).y1 = pivots(selFrame, pivots(selFrame,i).p ).y2
        pivots(selFrame,i).x2 = pivots(selFrame,i).x1 + cos(angle*DtoR) * pivots(selFrame,i).s
        pivots(selFrame,i).y2 = pivots(selFrame,i).y1 + sin(angle*DtoR) * pivots(selFrame,i).s
        
           'draw isometric view
        
            pz1 = pivots(selFrame,i).z1-20
            px1 = pivots(selFrame,i).x1
            py1 = pivots(selFrame,i).y1
    
            rz1 = (Cos(angle2*DtoR) * pz1 - Sin(angle2*DtoR) * px1)
            rx1 = (Sin(angle2*DtoR) * pz1 + Cos(angle2*DtoR) * px1)            
            ry1 = py1
            
            pz2 = pivots(selFrame,i).z2-20
            px2 = pivots(selFrame,i).x2
            py2 = pivots(selFrame,i).y2
            
            rz2 = (Cos(angle2*DtoR) * pz2 - Sin(angle2*DtoR) * px2)
            rx2 = (Sin(angle2*DtoR) * pz2 + Cos(angle2*DtoR) * px2)
            ry2 = py2
            
            LINEXYZ(rx1+320,ry1+240,rz1,rx2+320,ry2+240,rz2)

    next i

'==================================================================================
    for i as integer = 0 to TBONES
        color pivots(selFrame2,i).c
        if pivots(selFrame2,i).r = 1 then angle = pivots(selFrame2,0).a
        if pivots(selFrame2,i).a < 0   then pivots(selFrame2,i).a = pivots(selFrame2,i).a + 360
        if pivots(selFrame2,i).a > 359 then pivots(selFrame2,i).a = pivots(selFrame2,i).a - 360
        angle = angle + pivots(selFrame2,i).a
        if angle < 0   then angle = angle + 360
        if angle > 359 then angle = angle - 360
        pivots(selFrame2,i).x1 = pivots(selFrame2, pivots(selFrame2,i).p ).x2
        pivots(selFrame2,i).y1 = pivots(selFrame2, pivots(selFrame2,i).p ).y2
        pivots(selFrame2,i).x2 = pivots(selFrame2,i).x1 + cos(angle*DtoR) * pivots(selFrame2,i).s
        pivots(selFrame2,i).y2 = pivots(selFrame2,i).y1 + sin(angle*DtoR) * pivots(selFrame2,i).s
        
            'draw isometric view
            pz1 = pivots(selFrame2,i).z1+20
            px1 = pivots(selFrame2,i).x1
            py1 = pivots(selFrame2,i).y1
    
            rz1 = (Cos(angle2*DtoR) * pz1 - Sin(angle2*DtoR) * px1)
            rx1 = (Sin(angle2*DtoR) * pz1 + Cos(angle2*DtoR) * px1)            
            ry1 = py1
            
            pz2 = pivots(selFrame2,i).z2+20
            px2 = pivots(selFrame2,i).x2
            py2 = pivots(selFrame2,i).y2
            
            rz2 = (Cos(angle2*DtoR) * pz2 - Sin(angle2*DtoR) * px2)
            rx2 = (Sin(angle2*DtoR) * pz2 + Cos(angle2*DtoR) * px2)
            ry2 = py2
            
            LINEXYZ(rx1+320,ry1+240,rz1,rx2+320,ry2+240,rz2)
            
'=================================================================================================

    next i

    screenunlock
end sub

dim as string key
dim as integer mx,my,mb

drawBones()

dim as single dd,dx,dy

do
    selFrame = selFrame + 1
    if selFrame > 8 then selFrame = 1
    selFrame2 = selFrame2 + 1
    if selFrame2 > 8 then selFrame2 = 1
    drawBones()

    sleep 200
loop until  multikey(&H01)

DATA  0,0,0,0,1,356,48,0,0,94,44,1,0,329,40,2,0,302,18,3,1,180,48,0,0,266,40,5,0,0,36,6,0,275,22,7
DATA  0,0,0,0,1,356,48,0,0,110,44,1,0,314,40,2,0,304,18,3,1,180,48,0,0,263,40,5,0,20,36,6,0,262,22,7
DATA  0,0,0,0,1,0,48,0,0,118,44,1,0,314,40,2,0,289,18,3,1,180,48,0,0,265,40,5,0,27,36,6,0,259,22,7
DATA  0,0,0,0,1,0,48,0,0,126,44,1,0,317,40,2,0,278,18,3,1,180,48,0,0,287,40,5,0,22,36,6,0,261,22,7
DATA  0,0,0,0,1,8,48,0,0,130,44,1,0,299,40,2,0,284,22,3,1,180,48,0,0,262,40,5,0,51,36,6,0,243,22,7
DATA  0,0,0,0,1,0,48,0,0,143,44,1,0,275,40,2,0,80,18,3,1,180,48,0,0,252,40,5,0,0,36,6,0,281,22,7
DATA  0,0,0,0,1,0,48,0,0,114,44,1,0,270,40,2,0,80,18,3,1,177,48,0,0,250,40,5,0,3,36,6,0,289,22,7
DATA  0,0,0,0,1,0,48,0,0,94,44,1,0,304,40,2,0,346,18,3,1,180,48,0,0,258,40,5,0,0,36,6,0,283,22,7


Post Reply