home *** CD-ROM | disk | FTP | other *** search
- ; \|/
- ; O O
- ; --------------------------------oOO--U--OOo--------------------------------
- ; | |
- ; | Randomly Shaded Splines (RSS) Shape Blending. |
- ; | By Alain BROBECKER and Frederic ELISEI. |
- ; | (Baah and Armoric of Arm's Tech) |
- ; | Sept-Oct 95 |
- ; ---------------------------------------------------------------------------
- ;
- ; The source code is separated in three parts, which are...
- ; - the main demo. (Shape blending between splines)
- ; - filaments code generation.
- ; - routine which draws a RSS.
- ;
- ; The main part is, as usual not all that interesting. The main idea
- ; behind it is a linear interpolation between the control brows of the
- ; different splines composing the objects. I must admit that this shape
- ; blending is totally user defined. (Look at RSS_Ed)
- ; The intersting idea in here is to draw a spline with a fixed amount of
- ; random shadedots around each of the points in the spline. My first version
- ; was totally realtime, but I spent a week-end at ArmOric' s house and he
- ; gave me the idea to use generated code for each random shadedots filament.
- ;
- ; >-------------------------------------------------------------------------<
- ; The full credits are going like this...
- ; - Idea and coding by Baah / Arm' s Tech.
- ; - Generated code idea by Armoric / Arm's Tech.
- ; - Spline rout by Baah, with inspiration from Jan / BASS.
-
- #set rss_shift=6 ; premul factor=n.
- #set rss_nb_pts=129 ; nb of points in the spline=1+2^(n+1).
- ;#set rss_time = 300 ; Time a shape stays on screen.
- #set rss_splines_nb = 16 ; Nb of splines per shape.
- #set rss_images_nb = 7 ; Nb of successive shapes.
- #set rss_routs_nb = 32 ; Nb of filaments routines to generate/2.
- #set rss_nb_rnd = 13 ; Nb of points drawn per generated rout.
-
- ;****************************************************************************
- ;***** *****
- ;***** RSS Shape Blending *****
- ;***** *****
- ;****************************************************************************
- ; This is the part of the proggy which actually displays the forms on the
- ; screen, with shape blending between two shapes. It is not very hard to
- ; understand, so I won' t talk more here.
- ; Parameter for this demo part....
- ; r0 = adress of a megabuffer used for creation of the generated code.
-
- .rss_part
- stmfd r13!,{r0-r12,r14}
- str r0,_megabuffer_ad ; Generate code for the filaments.
- add r0,r0,#rss_nb_pts*8
- bl rss_generate_code
- adr r2,_rss_colors ; Change colors.
- bl set_palette
-
- ._shape_blending
- mov r0,#64 ; Nb of steps for one shape blending.
- str r0,_blend_counter
- ._blend_one_frame
- bl wait_and_swap ; Wait vsync, swap screens, r0=workscreen.
- mov r1,#&ff
- bl clear_mode9 ; Clear screen.
- adr r1,_animation ; r1=adress of current shape.
- ldr r2,_current_inc_ad ; r2=adress of current increments.
- mov r14,#rss_splines_nb ; Nb of splines to blend.
- ._blend_one_spline
- ldmia r1,{r3-r6} ; The 'shape blending' is in fact
- ldmia r2!,{r7-r10} ; a stupid linear interpolation between
- add r3,r3,r7 ; the control brows of two images.
- add r4,r4,r8
- add r5,r5,r9
- add r6,r6,r10
- stmia r1!,{r3-r6}
- ldmia r1,{r3-r6}
- ldmia r2!,{r7-r10}
- add r3,r3,r7
- add r4,r4,r8
- add r5,r5,r9
- add r6,r6,r10
- stmia r1!,{r3-r6}
- subS r14,r14,#1 ; One spline 'blended'.
- bNE _blend_one_spline
-
- ; Time to draw the image on screen.
- sub r2,r1,#32*rss_splines_nb ; r2 points on current shape.
- ldr r10,_megabuffer_ad ; A buffer needed by the RSS routine.
- add r1,r10,#rss_nb_pts*8 ; r1 points on the filaments routines.
- mov r12,#rss_splines_nb ; Nb of splines to draw.
- ._blending_draw
- bl random_shade_spline
- add r2,r2,#8*4 ; Next spline coords.
- subS r12,r12,#1 ; It was last spline?
- bNE _blending_draw
-
- ldr r0,_blend_counter ; r0=nb of times still to blend.
- subS r0,r0,#1
- strNE r0,_blend_counter
- bNE _blend_one_frame
-
- ; Prepare things for next shape blending.
- ._next_image
- ldr r0,_current_inc_ad
- add r0,r0,#32*rss_splines_nb
- str r0,_current_inc_ad
- ldr r0,_image_counter
- subS r0,r0,#1
- cmp r0,#1
- ldmLEfd r13!,{r0-r12,pc} ; Quit if it was last image.
- str r0,_image_counter
-
- ; Ok, we had better let the shape as is for some time, else the demolovers
- ; won' t be able to look at the wonderfull graphics.
- bl fix_time
- ._wait_one_frame
- bl wait_and_swap ; Wait vsync, swap screens, r0=workscreen.
- mov r1,#&ff
- bl clear_mode9 ; Clear screen.
- ldr r10,_megabuffer_ad ; A buffer needed by the RSS routine.
- add r1,r10,#rss_nb_pts*8 ; r1 points on the routines.
- adr r2,_animation
- mov r12,#rss_splines_nb ; Nb of splines to draw.
- ._wait_draw
- bl random_shade_spline
- add r2,r2,#8*4 ; Next spline coords.
- subS r12,r12,#1 ; It was last spline?
- bNE _wait_draw
- bl read_time ; r0=time elapsed.
- cmp r0,#rss_time
- bLE _wait_one_frame
-
- b _shape_blending
-
- ; ===========================================================================
- ; = =
- ; = MAIN DATAS =
- ; = =
- ; ===========================================================================
-
- ._rss_colors
- dcb &ff,&ff,&aa,&ff,&ee,&88,&ff,&dd,&66,&ff,&cc,&44
- dcb &ff,&bb,&22,&ff,&aa,&00,&ee,&88,&00,&dd,&66,&00
- dcb &cc,&44,&00,&bb,&22,&00,&aa,&00,&00,&88,&00,&00
- dcb &66,&00,&00,&44,&00,&00,&22,&00,&00,&00,&00,&00
-
- ._megabuffer_ad
- dcd 0
-
- ._animation
- incbin RSS_Ed.RSS_anim
-
- ._blend_counter
- dcd 0
-
- ._image_counter
- dcd rss_images_nb
-
- ._current_inc_ad
- dcd _animation+32*rss_splines_nb
-
-
- ;****************************************************************************
- ;***** *****
- ;***** Code Generator *****
- ;***** *****
- ;****************************************************************************
- ;
- ; This routine creates a certain amount of routine which are drawing random
- ; filaments. This allows fast shading (on Arm2 it proves much faster) because
- ; we don' t need to perform the random walk of the filament in realtime, but
- ; instead we randomly choose a filament routine. Also, when we shade pixel
- ; we exactly know where it is in the byte, and it is much easier. (At first
- ; I was using a shadedot routine accessing to longwords, with lotsa masking
- ; and the like) So the generated code is a succession of...
- ; x even ldrB r6,[r7,#offset] ; Load byte.
- ; tst r6,#&f ; 4 lowerbits of r1=0?
- ; subNE r6,r6,#1 ; No, then shade the pixie.
- ; strB r6,[r7,#offset] ; And save modified byte.
- ; x odd ldrB r6,[r7,#offset] ; Load byte.
- ; subS r6,r6,#1<<4 ; Shade pixel in the 4 upperbits.
- ; strPLB r6,[r7,#offset] ; If pixel color>=0, save byte.
- ;
- ; As I said earlier the idea of generating code was brought up by ArmOric.
- ; He told it to me, and after the night we both came with exactly the same
- ; instruction sequence (the one above), so I doubt you can find something
- ; faster on Arm2. I must admit that before we went to sleep Fred was knowing
- ; the solution, but I asked him not to tell it to me, so that I proved myself
- ; I' m able to be as good as Fred. (I was a bit ashamed when Fred talked
- ; about using generated code, cos I' m supposed to be the expert in this!)
- ; Anyway, again lots of thanks to Fred for his help.
- ;
- ; >-------------------------------------------------------------------------<
- ; Parameters of the generated routines...
- ; r0=videoram adress of the start of the filament.
- ; r14=return adress.
- ; r1 will be modified!
- ;
- ; >-------------------------------------------------------------------------<
- ; Parameters of generating routine...
- ; r0=adress of a buffer, which will contain the table of all
- ; the routines adresses, and after this table, the code of
- ; the generated routines.
- ; The routines between 0 and (rss_rout_nb-1) assumes x pos is even, and
- ; routines between rss_rout_n and (2*rss_rout_nb-1) assumes x pos is odd.
-
- .rss_generate_code
- stmfd r13!,{r0-r12,r14} ; Clean...
- str r13,rss_old_stack
- add r1,r0,#rss_routs_nb*8 ; r1 points where to generate code.
- adr r2,rss_directions
- ldmdb r2,{r3,r4} ; r3 and r4 are random germs.
- adr r5,_opcodes ; r5 points on opcodes used.
- mov r6,#rss_routs_nb*2 ; Counts the nb of generated routs.
- ._gen_one_rout
- str r1,[r0],#4 ; Save adress of the routine.
- mov r7,#rss_nb_rnd ; r7=nb of rnd points per filament.
- mov r8,#0 ; r8=x pos of first pixie,
- cmp r6,#rss_routs_nb ; =0 for the first routs.
- movLE r8,#1 ; =1 for the last ones.
- mov r9,#0 ; r9=y offset.
- ._gen_one_pixie
- add r10,r9,r8,asr #1 ; r10=offset.
- tst r8,#1 ; Pixel in upperbits or lowerbits?
- bEQ _gen_up
- ; The pixel is in the 4 lowerbits. Generate code for it.
- ldmia r5,{r11-r13} ; Load opcodes.
- cmp r10,#0 ; Offset negative?
- bicMI r11,r11,#1<<23 ; Yes, then notify it in ldrB & strB.
- bicMI r13,r13,#1<<23
- rsbMI r10,r10,#0 ; r10=abs(offset).
- add r11,r11,r10 ; r11='ldrB r6,[r6,#offset]'.
- add r13,r13,r10 ; r14='strPLB r6,[r7,#offset]'.
- stmia r1!,{r11-r13} ; Generate code.
- and r10,r3,#%111 ; r10=rnd(8).
- add r10,r2,r10,lsl #3 ; r10 points on the good direction.
- ldmia r10!,{r10,r11} ; r10=dx | r11=dy.
- add r8,r8,r10 ; x_pos+=dx.
- add r9,r9,r11 ; y_offset+=dy.
- add r3,r4,r3,ror #3 ; Next random number.
- mov r3,r3,ror r4
- eor r4,r3,r4,ror #7
- subS r7,r7,#1 ; One pixie generated
- bNE _gen_one_pixie
- ldr r10,[r5,#12] ; r10='mov pc,r14'.
- str r10,[r1],#4 ; Generate it.
- subS r6,r6,#1 ; One filament routine generated.
- bNE _gen_one_rout
- ldr r13,rss_old_stack ; Finished...
- ldmfd r13!,{r0-r12,pc}
-
- ; The pixel is in the 4 upperbits. Generate code for it.
- ._gen_up
- ldmdb r5,{r11-r14} ; Load opcodes.
- cmp r10,#0 ; Offset negative?
- bicMI r11,r11,#1<<23 ; Yes, then notify it in ldrB & strB.
- bicMI r14,r14,#1<<23
- rsbMI r10,r10,#0 ; r10=abs(offset).
- add r11,r11,r10 ; r11='ldrB r6,[r7,#offset]'.
- add r14,r14,r10 ; r14='strNEB r6,[r7,#offset]'.
- stmia r1!,{r11-r14} ; Generate code.
- and r10,r3,#%111 ; r10=rnd(8).
- add r10,r2,r10,lsl #3 ; r10 points on the good direction.
- ldmia r10!,{r10,r11} ; r10=dx | r11=dy.
- add r8,r8,r10 ; x_pos+=dx.
- add r9,r9,r11 ; y_offset+=dy.
- add r3,r4,r3,ror #3 ; Next random number.
- mov r3,r3,ror r4
- eor r4,r3,r4,ror #7
- subS r7,r7,#1 ; One pixie generated
- bNE _gen_one_pixie
- ldr r10,[r5,#12] ; r10='mov pc,r14'.
- str r10,[r1],#4 ; Generate it.
- subS r6,r6,#1 ; One filament routine generated.
- bNE _gen_one_rout
- ldr r13,rss_old_stack ; Finished....
- ldmfd r13!,{r0-r12,pc}
-
- ; The opcodes used by the generated code.
- ldrB r6,[r7,#0] ; Routine when x is even.
- tst r6,#&f
- subNE r6,r6,#1
- strNEB r6,[r7,#0]
- ._opcodes
- ldrB r6,[r7,#0] ; Routine when x is odd.
- subS r6,r6,#1<<4
- strPLB r6,[r7,#0]
- mov pc,r14 ; Well, mysterious instruction, huh?
-
- .random_germs
- dcd &eb1a2c37,&3fd2a145
- .rss_directions
- dcd 0,160,0,-160,1,0,-1,0
- dcd 1,160,-1,160,1,-160,-1,-160
-
- .rss_old_stack ; Well...
- dcd 0
-
-
-
-
- ;****************************************************************************
- ;***** *****
- ;***** Randomly Shaded Spline *****
- ;***** *****
- ;****************************************************************************
- ;
- ; This routine draws a randomly shaded spline. We calculate a fixed amount
- ; of points in the spline, and save them in a table. Then, for each of this
- ; point, we randomly choose a filament, and jump at the corresponding rout.
- ; The clipping is performed individually for each filament. If the box
- ; around the point (and 'radius' of the box being maximum length of filament)
- ; is out of the screen or even partially clipped, we quite simply don' t draw
- ; the filament.
- ; The full incremental spline calculation trick was found in a spline rout
- ; by Jan/BASS, and then rewritten by me. (I don' t have exactly the same
- ; spline formulas as Jan does) As usual, Jan' s code is a very good source
- ; of inspiration. :)
- ; The x clipping was 'removed' because it was unusefull in this demo.
- ;
- ; >-------------------------------------------------------------------------<
- ; Parameters are...
- ; r0=adress of workscreen.
- ; r1=adress of the table of routines adresses.
- ; r2=adress of spline control brows. (x0,y0,x1,y1,x2,y2,x3,y3)*64
- ; r10=adress of a 129*2 longs buffer.
-
- .random_shade_spline
- stmfd r13!,{r0-r12,r14} ; Be clean or crash!
- ldmia r2,{r2-r9} ; Load spline control brows.
- mov r2,r2,asr #6 ; Take integer part of their x coord.
- mov r4,r4,asr #6
- mov r6,r6,asr #6
- mov r8,r8,asr #6
- ; cmp r2,#320 ; If all the control brows are on right
- ; cmpGE r4,#320 ; of the screen, then the whole spline
- ; cmpGE r6,#320 ; is on right of the screen ->quit.
- ; cmpGE r8,#320
- ; ldmGEfd r13!,{r0-r12,pc}
- ; cmp r2,#0 ; Same comment when all brows on left.
- ; cmpLT r4,#0
- ; cmpLT r6,#0
- ; cmpLT r8,#0
- ; ldmLTfd r13!,{r0-r12,pc}
- mov r3,r3,asr #6 ; Take integer part of y coords.
- mov r5,r5,asr #6
- mov r7,r7,asr #6
- mov r9,r9,asr #6
- cmp r3,#256 ; All brows below?..
- cmpGE r5,#256
- cmpGE r7,#256
- cmpGE r9,#256
- ldmGEfd r13!,{r0-r12,pc}
- cmp r3,#0 ; Or above the screen.
- cmpLT r5,#0
- cmpLT r7,#0
- cmpLT r9,#0
- ldmLTfd r13!,{r0-r12,pc}
-
- ; Now, using the coords of the control brows, we calculate the x and y
- ; compounds of the cubic spline coefficients, which are...
- ; a0=p0
- ; a1=4*p1-4*p0
- ; a2=-p3+4*p2-8*p1+5*p0
- ; a3=2*p3-4*p2+4*p1-2*p0
- mov r4,r4,lsl #2 ; r4=4x1.
- sub r11,r4,r2,lsl #1
- add r11,r11,r8,lsl #1
- sub r11,r11,r6,lsl #2 ; r11=a3x=2x3-4x2+4x1-2x0.
- rsb r6,r8,r6,lsl #2
- add r6,r6,r2,lsl #2
- add r6,r6,r2
- sub r6,r6,r4,lsl #1 ; r6=a2x=-x3+4x2-8x1+5x0.
- sub r4,r4,r2,lsl #2 ; r4=a1x=4x1-4x0.
- mov r5,r5,lsl #2 ; r5=4y1.
- sub r12,r5,r3,lsl #1
- add r12,r12,r9,lsl #1
- sub r12,r12,r7,lsl #2 ; r12=a3y=2y3-4y2+4y1-2y0.
- rsb r7,r9,r7,lsl #2
- add r7,r7,r3,lsl #2
- add r7,r7,r3
- sub r7,r7,r5,lsl #1 ; r7=a2y=-y3+4y2-8y1+5y0.
- sub r5,r5,r3,lsl #2 ; r5=a1y=4y1-4y0.
- ; So, here we have the following...
- ; r2 = a0x | r3 = a0y
- ; r4 = a1x | r5 = a1y
- ; r6 = a2x | r7 = a2y
- ; r11 = a3x | r12 = a3y
- ; Now, in order to work in a totally incremental way, we calculate
- ; inc1=a1*h+a2*h^2+a3*h^3
- ; inc2=2*a2*h^2+6*a3*h^3
- ; inc3=6*a3*h^3
- ; Please note that we must convert all values in fixed point.
- mov r2,r2,lsl #rss_shift*3 ; r2=a0x.
- add r4,r6,r4,lsl #rss_shift
- add r4,r11,r4,lsl #rss_shift ; r4=inc1x=a1x*h+a2x*h^2+a3x*h^3.
- add r8,r11,r11,lsl #1
- mov r8,r8,lsl #1 ; r8=inc3x=6*a3x*h^3.
- add r6,r8,r6,lsl #rss_shift+1 ; r6=inc2x=2*a2x*h^2+6*a3x*h^3.
- mov r3,r3,lsl #rss_shift*3 ; r3=a0y.
- add r5,r7,r5,lsl #rss_shift
- add r5,r12,r5,lsl #rss_shift ; r5=inc1y=a1y*h+a2y*h^2+a3y*h^3.
- add r9,r12,r12,lsl #1
- mov r9,r9,lsl #1 ; r9=inc3y=6*a3y*h^3.
- add r7,r9,r7,lsl #rss_shift+1 ; r7=inc2y=2*a2y*h^2+6*a3y*h^3.
- ; It' s time to calculate the points of the spline and save them in the
- ; buffer pointed by r1. Note that in order to increase the number of points
- ; in a convenient way, half of them are calculated using a stupid linear
- ; interpolation. Less accurate, but a bit faster.
- #rept 64
- add r11,r2,r4,asr #1 ; [r10|r11]=M+0.5*inc1.
- add r12,r3,r5,asr #1
- stmia r10!,{r2,r3,r11,r12} ; Save M and M+0.5*inc1.
- add r2,r2,r4 ; M=M+inc1.
- add r3,r3,r5
- add r4,r4,r6 ; inc1=inc1+inc2.
- add r5,r5,r7
- add r6,r6,r8 ; inc2=inc2+inc3.
- add r7,r7,r9
- #endr
- stmia r10!,{r2,r3} ; Save the last point.
-
- ; Time to draw the filaments of the spline.
- ; Here we have the following...
- ; r0=adress of workscreen.
- ; r1=adress of the table of routines adresses.
- ; r10 points after the points coords.
- sub r2,r10,#rss_nb_pts*8 ; r2 points on the coords buffer.
- adr r3,random_germs
- ldmia r3,{r3,r4} ; r3 & r4 are random numbers.
- mov r5,#rss_nb_pts ; Nb of filaments to draw.
- adr r14,rss_one_set ; Return adress.
- .rss_one_set
- add r3,r4,r3,ror #3 ; Next random number generation.
- mov r3,r3,ror r4
- eor r4,r3,r4,ror #7
- subS r5,r5,#1 ; One filament processed.
- bMI rss_the_end
- ldmia r2!,{r6,r7} ; r6=x<<rss_shift*3 | r7=y<<rss_shift*3.
- mov r6,r6,asr #rss_shift*3 ; r6=int(x).
- ; cmp r6,#rss_nb_rnd ; Set of pixels clipped or out?
- ; bMI rss_one_set
- ; cmp r6,#320-rss_nb_rnd
- ; bGE rss_one_set
- mov r7,r7,asr #rss_shift*3 ; r7=int(y).
- cmp r7,#rss_nb_rnd ; Set of pixels clipped or out?
- bMI rss_one_set
- cmp r7,#256-rss_nb_rnd
- bGE rss_one_set
- add r7,r7,r7,lsl #2 ; Make r6 point on good byte.
- add r7,r0,r7,lsl #5
- add r7,r7,r6,asr #1
- tst r6,#1 ; Flags=int(x) and 1.
- and r6,r3,#rss_routs_nb-1 ; r6=rnd(rss_routs_nb-1).
- addNE r6,r6,#rss_routs_nb
- ldr pc,[r1,r6,lsl #2] ; Execute the chosen routine.
-
- .rss_the_end
- adr r2,random_germs
- stmia r2,{r3,r4} ; Save the modified random germs.
- ldmfd r13!,{r0-r12,pc} ; The end.
-