English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 20 November 2020, 21:12   #1
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
HAM Fill demo effects

Hello Demo Coders

I've been exploring a rare OCS demo technique that uses HAM mode to fill polygons. I was wondered if anyone (other than Photon) has given this a try? Or does anyone have thoughts on how to work around the glitches I'm still trying to fix?

You might not know what I'm talking about so I'll try to explain the technique and link to some examples.

The idea is that you use HAM mode to automatically fill pixel spans for your polygons.

You start with a HAM5 screen with the 5th bit-plane completely filled with ones. In such a setup all pixel colors are the result of copying the color from the left neighbor and then replacing the blue channel with whatever value is in planes 1-4. This sets things up so any red or green pixels will repeat across the span and the blue value will be set to zero.

To start a span you need to set the left edge pixel so planes 1-4 select the color you want and then clear the plane 5 pixel so HAM will know to look up this pixels color. Having drawn the left pixel the rest of the span will repeat the red and green color for the rest of the scan-line, which is as we expect from our initial setup. You then end the span by writing a pixel to select the background color.

So, in order to draw a polygon object you only need to draw the left edges of polygons and any terminating right edges. You don't need to do any explicit fill operation. Since there's no need for a fill pass the Blitter can be dedicated exclusively to rendering lines. In theory this should free up time to render larger more complex objects. In practice it's a little harder to see the gains you might expect, mostly because you'll have to draw a lot of lines and also because you need to enable 5 bit-planes.

The other downside if it wasn't obvious is that you can't use any blue in the image.

That's the theory and here's the only examples I know of:

Last A500 by Oblivion (the large cube before the end section)
https://www.pouet.net/prod.php?which=64898

Blu Sky by Scoopex (the orange poly shapes before the end section)
https://www.pouet.net/prod.php?which=66264
[ Show youtube player ]

The trouble with this technique however is that it's difficult to efficiently render the lines in such a way that they don't interfere with one another leading to the wrong pixel color starting or ending a span.

My implementation currently doesn't avoid the problem at all. It's most obvious at shared vertices. The color for a shared vertex ends up being some combination of the pixels drawn for all the converging lines. This problem becomes worse when the edges start coming together at acute angles, at which point multiple pixels start to overlap with the wrong color.

Here's my work in progress so you can see what I mean:
[ Show youtube player ]

In the Oblivion example Boogeyman has avoided these problems by reducing the colors used and setting up the palette so lines that overlap will still select the same color.

In Blu Sky it looks like Photon is somehow spacing the lines out horizontally and back-facing polygons early to avoid overlaps. However this doesn't remove all the artifacts and the overall look isn't as clean as I'd like.

The root of the problem for my implementation is that the lines are overlapping and I'm only drawing lines to turn pixels on, not to turn them off. I'm trying to come up with a solution that will solve all the glitches but won't add too much extra overhead.

At first I thought I might be able to exploit skipping the first pixel of each line to fix the vertices, but I haven't found a scheme where that helps me out.

More generally it seems like sorting the lines from left to right and rendering the zero pixels for any overlap would solve things. But this seems like it'll just get too expensive with all those zero lines and the sorting part would probably take too long.

I'm feeling a little stuck with this tricky technique but not ready to give up yet. I'd love to hear any suggestions!

Thanks
Jobbo
Jobbo is offline  
Old 21 November 2020, 00:06   #2
TEG
Registered User

 
Join Date: Apr 2017
Location: France
Posts: 56
This is genius :-)

The Scoopex demo is very impressive. Thanks to solved the mystery behind!

I hope you will find a solution for your problem.
TEG is offline  
Old 21 November 2020, 00:14   #3
no9
Registered User

no9's Avatar
 
Join Date: Feb 2018
Location: Poland
Posts: 135
I like those glitches. Add more
no9 is offline  
Old 21 November 2020, 01:48   #4
mr.spiv
Registered User
mr.spiv's Avatar
 
Join Date: Aug 2006
Location: Finland
Age: 48
Posts: 160
I have a faint memory that Freddy's old 3D demo for Phoenix from -89 used HAM filling. I could be wrong.. I recall it also used copper driven blitter. Gotta take a closer look at that gem..
mr.spiv is offline  
Old 21 November 2020, 13:00   #5
hooverphonique
ex. demoscener "Bigmama"

 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,194
I haven't thought about this in detail, but the glitches look much like the ones you get when using traditional blitter line+fill (although the artifacts go right to left), so maybe that will give you a hint at how to get rid of them.
hooverphonique is offline  
Old 21 November 2020, 19:18   #6
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
Quote:
Originally Posted by mr.spiv View Post
I have a faint memory that Freddy's old 3D demo for Phoenix from -89 used HAM filling. I could be wrong.. I recall it also used copper driven blitter. Gotta take a closer look at that gem..

I found the demo you were thinking of:
https://www.pouet.net/prod.php?which=14484


Checked it out and confirmed it's HAM fill! Even shows some of the same artifacts.


It's an unusual choice in this demo given how few colors it's using.
Jobbo is offline  
Old 21 November 2020, 20:07   #7
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
Quote:
Originally Posted by hooverphonique View Post
I haven't thought about this in detail, but the glitches look much like the ones you get when using traditional blitter line+fill (although the artifacts go right to left), so maybe that will give you a hint at how to get rid of them.

It's a very similar problem.


As I understand it when filling with the blitter it's normal to use the exclusive fill mode which will erase the right edges. I can achieve the same by drawing lines to clear the right edges.


What I'm not sure of is how to do this in the most efficient way possible. I'll have to give it more thought.


I've not tried the fill with the blitter approach before trying this HAM fill trick. So maybe if I knew more about that it would help.


How do others select the optimal number of lines to draw for 16 color poly objects using the fill approach?
Jobbo is offline  
Old 21 November 2020, 21:21   #8
DanScott
Lemon. / Core Design

DanScott's Avatar
 
Join Date: Mar 2016
Location: Tier 2
Posts: 753
You need to ensure that lines are always drawn down the screen, and (as far as I remember) subtract 1 from the height of the line
DanScott is offline  
Old 24 December 2020, 04:57   #9
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
I’m still chipping away at this problem. I’ve made decent progress but find I need line drawing that will skip the first pixel or skip the last pixel or skip both the first and last pixels.

I know I can set bltdpt to some scratch area to skip the first pixel. And I can just draw the line from end to start if I only want to skip the last pixel (accepting that the line will not be 100% as it would be otherwise).

But to skip both first and last I’m setting bltsize so I don’t add the extra 1 in “dx + 1”. This seems like it works but the line isn’t exactly the same as it should be.

Does anyone know what happens when you do this? What if dx is actually zero? What does bltsize “dx + 1” really mean?

Last edited by Jobbo; 24 December 2020 at 05:07.
Jobbo is offline  
Old 24 December 2020, 10:47   #10
Antiriad_UK
OCS forever!

Antiriad_UK's Avatar
 
Join Date: Mar 2019
Location: Birmingham, UK
Posts: 335
Make your routine always draw from top to bottom (just test y1 vs y2). Use bltdpt trick to skip first pixel. Subtract 1 from dy to skip last pixel (this feels like it shouldn’t work but does). Also skip any lines where y1 = y2.

Edit: Here's the filled line "prototyping" code I use for filled lines using the dy-1 method which may give some ideas. You fill in the line/bitplane modulo values in PRO_Line_Fill_Vars, then call PRO_Line_Fill_Draw_Init once, then call PRO_Line_Fill_Draw for as many lines as needed. Edit this routine also draws inverted lines as that's the trick needed when trying to draw all lines on a simple/glenz object and fill in a single pass (think shared edges, drawing the same line twice removes it so it fills as a single surface) - that might not be needed for you.
Code:
*****************************************************************************
* Calcs and draws a line in one go. Multiple bitplanes.
* Routine ensures that y2>y1 and draws from top of screen to bottom.
* Two ways of removing a corner (for blitter fill):
* - Point bltdpth to a blank word. This causes the FIRST pixel (top) to be
* not written to screen. In this case first scanline is never touched.
* - Reduce dy by one, which seems a kludge but seems to work. In this case
* the last scanline (bottom) is not drawn and is also slightly faster (one less y).
*
* IN:		a6, _custom)
*		a0, screen address
*		a1, linedraw premult table must match the modulo
*		d0-d3, x,y,x2,y2 of the line to draw
* OUT:		
* TRASHED:	d0-d1/a0
*****************************************************************************

	xdef PRO_Line_Fill_Draw_Init
PRO_Line_Fill_Draw_Init:				;T:d0/a0
	lea	PRO_Line_Fill_Vars(pc),a0
	moveq	#-1,d0
	WAITBLIT_NASTY_A6
	move.l	d0,bltafwm(a6)				;mask
	move.w	PRO_LINE_MOD_LINE(a0),bltcmod(a6)	;modulo, DMOD NOT required
	move.w	PRO_LINE_TEXTURE(a0),bltbdat(a6)	;texture
	move.w	#$8000,bltadat(a6)
	rts

	xdef PRO_Line_Fill_Draw
PRO_Line_Fill_Draw:
	movem.l	d2-d4,-(sp)

	;The linedraw routine draws from top of screen to bottom. We want
	;y2 > y1 for the logic used.
	sub.w 	d1,d3			;dy
	beq	.NoDrawLine		;skip when y1=y2
	bpl.b	.line1			;ensure y2>y1
	exg	d0,d2				
	neg.w	d3			
	sub.w	d3,d1			
.line1:
	subq	#1,d3			;dy-1 for blit corner fix, last pixel not plotted

	move.l	#$a4a0000f,d4		;$4a=inverted line, $ca=normal
	and.w	d0,d4			;x & 15
	ror.l	#4,d4			;get shift value in top of word for bltcon0, low word cleared for move.b later

	sub.w	d0,d2			;dx
	bpl.b	.line2
	neg.w	d2			;make dx postive
	addq	#2,d4
.line2:					
	; Mulu y version
	lsr.w	#3,d0			;x1 to byte offset, odd address ignored
	mulu	.vars+PRO_LINE_MOD_LINE(pc),d1
	add.l	d1,a0			;update with yoffset, y maybe > 32767 so need to use add.l
	add.w	d0,a0			;update with xoffset, a0 is final screen address
	; ----
	; Table y lookup version, ;ASSERT: d0/d1 are positive.
;	lsr.w	#3,d0			;x1 to byte offset, odd address ignored
;	add.w	d1,d1			;y table access offset in words
;	add.w	LINEDRAW_MULT(a1,d1.w),d1	;pdate with yoffset
;	add.w	d0,a0			;update with xoffset, a0 is final screen address
	;---

	cmp.w	d2,d3
	bmi.b	.line3
	addq	#1,d4					
	exg	d2,d3
.line3:
	move.w	d3,d1			;dy
	add.w	d1,d1			;2*dy; bltbmod
	swap	d1			;bltbmod in top word
	move.w	d3,d1
	sub.w	d2,d1			;dy-dx
	add.w	d1,d1			;2*(dy-dx) ; bltamod	
					;d1.l = bltbmod/bltamod
	add.w	d3,d3
	sub.w	d2,d3			;(2*dy)-dx ; bltaptl
	addx.w	d4,d4
	move.b	.octants(pc,d4.w),d4	;d4.l now bltcon0/1 (top of d4.w is 0 before this)

	addq.w	#1,d2			;dx+1
	lsl.w	#6,d2			;move to bits 15-6
	addq.w	#2,d2			;bltsize

	move.w  .vars+PRO_LINE_COLOR(pc),d0	;get required color
	lsr.w	#1,d0			;Color bit set?
	bcc.s	.nextbpl		;No, next bpl
.colorloop
	WAITBLIT_A6

	; NOTE: These three lines can be moved out if drawing loads of lines at once
	;move.l	#-1,bltafwm(a6)		;mask
	;move.w	.vars+PRO_LINE_MOD_LINE(pc),bltcmod(a6)	;modulo, DMOD NOT required
	;move.w	.vars+PRO_LINE_TEXTURE(pc),bltbdat(a6)	;texture
	;move.w	#$8000,bltadat(a6)
	; --------
		
	move.l	d4,bltcon0(a6)		;bltcon0/bltcon1
	move.l	d1,bltbmod(a6) 		;bltbmod/bltamod
	move.l  a0,bltcpth(a6) 
	move.w 	d3,bltaptl(a6)
	move.l  a0,bltdpth(a6) 
	;move.l	#FW_LineDraw_Scratch,bltdpth(a6) ;First pixel is written here (offscreen)
	move.w	d2,bltsize(a6)
.nextbpl:
	add.w	.vars+PRO_LINE_MOD_BPL(pc),a0	;next bitplane
	lsr.w	#1,d0				;check next bit 
	bcs.s	.colorloop			;bit set?
	bne.s	.nextbpl			;any color left?
.NoDrawLine:	

	movem.l	(sp)+,d2-d4
	rts

.octantbase equ 3				;1=normal,3=1px per line (fill)
.octants:
	dc.b	$10+.octantbase
	dc.b	$50+.octantbase
	dc.b	$00+.octantbase
	dc.b	$40+.octantbase
	dc.b	$14+.octantbase
	dc.b	$54+.octantbase
	dc.b	$08+.octantbase
	dc.b	$48+.octantbase

	xdef PRO_Line_Fill_Vars
.vars
PRO_Line_Fill_Vars:
	dc.w    0       		;PRO_LINE_COLOR
	dc.w	$ffff			;PRO_LINE_TEXTURE	
	dc.w	0			;PRO_LINE_MOD_LINE
	dc.w	0			;PRO_LINE_MOD_BPL

Last edited by Antiriad_UK; 24 December 2020 at 11:35.
Antiriad_UK is offline  
Old 24 December 2020, 11:40   #11
ross
Defendit numerus

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 50
Posts: 2,997
Hi Antiriad

Of course it's a great routine, very similar to mine but in the end they all look alike.

Just curious about the use of
d4
which i had never seen anywhere but in my routines.
You got it somewhere or you thought it up?
Only to understand how these algorithms develop and optimize over time and between one person and another
ross is offline  
Old 24 December 2020, 11:49   #12
DanScott
Lemon. / Core Design

DanScott's Avatar
 
Join Date: Mar 2016
Location: Tier 2
Posts: 753
just a quick note that really you should specify the size in an addq and subq instruction, as they can be .b .w or .l It's only a moveq that is fixed at .l
DanScott is offline  
Old 24 December 2020, 12:26   #13
Antiriad_UK
OCS forever!

Antiriad_UK's Avatar
 
Join Date: Mar 2019
Location: Birmingham, UK
Posts: 335
Quote:
Originally Posted by ross View Post
Hi Antiriad

Of course it's a great routine, very similar to mine but in the end they all look alike.

Just curious about the use of
d4
which i had never seen anywhere but in my routines.
You got it somewhere or you thought it up?
Only to understand how these algorithms develop and optimize over time and between one person and another
This bit?
Code:
	move.l	#$a4a0000f,d4		;$4a=inverted line, $ca=normal
	and.w	d0,d4			;x & 15
	ror.l	#4,d4			;get shift value in top of word for bltcon0, low word cleared for move.b later
...
...
	move.b	.octants(pc,d4.w),d4	;d4.l now bltcon0/1 (top of d4.w is 0 before this)
The entire routine is a merge of about every routines I've ever had my mucky paws on. I think my first one was the standard cryptoburners one for filled lines, then I saw some nice stuff in the Axis one from Planet Rock Lobster with a minterm table/dy-1 that I added. Then I saw one from leffman on EAB I think that did this:
Code:
	moveq	#15,d4   ; get first pixel bit-position and set
	and.b	d0,d4    ; other bits needed for BLTCON0
	ror.w	#4,d4
	or.w	#$a4a,d4
	swap	d4
Which got me thinking about quicker ways to AND in a similar way to how I did BOB shifts. This is the one I settled on so it must have been faster than the minterm table when I added it up in Easy68K. No doubt the relying on d4 being clear in the top will bite me at some point but that's what the comment is for Edit: Actually just checked my various routines and I think those 3 lines are from a Photon routine so more likely I got it from there

Another tweak yesterday I did was to save a few cycles with this change which combines the dx+1 * 64 + 2 :
Code:
	;addq.w	#1,d2			;dx+1
	;lsl.w	#6,d2			;move to bits 15-6
	;addq.w	#2,d2			;bltsize
	add.w	d2,d2			;table access in words
	move.w	.bltsize(pc,d2.w),d2	;bltsize is (dx+1)*64 + 2
...
...
;(dx+1)*64 + 2
.bltsize:
a set 0
	rept	BPL_BUF_WIDTH
	dc.w	((a+1)<<6)+2		
a set a+1
	endr
To be honest at this point unless the line is miniscule then it's all about the same. I did get an extra single BOB in my glenz bobs routine by going through the various routines though

Dan, yep, rookie error

Last edited by Antiriad_UK; 24 December 2020 at 12:40.
Antiriad_UK is offline  
Old 24 December 2020, 12:52   #14
ross
Defendit numerus

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 50
Posts: 2,997
Hahaha, great, you probably followed the same reasoning as me

Just checked but I've used this:
	move.l	#$b5a0000f,d4				; XOR unmasked

I don't remember why but probably to save some cycles to avoid setting the mask since I have to draw solid lines.

I searched if i left anything written around about minterms and i found only this:
https://eab.abime.net/showthread.php?t=99093

Unfortunately I often write things and then I don't remember where I left them, often only by email, file, snippet, notes and then who finds them anymore?
ross is offline  
Old 24 December 2020, 12:59   #15
JoeJoe
Registered User

 
Join Date: Feb 2020
Location: Germany
Posts: 75
This (Mysterious world of blitter line mode..) was very helpful for me. It explains the 1pixel problem in LineMode and how to work around it.
JoeJoe is online now  
Old 27 December 2020, 20:30   #16
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
Thanks for the responses.

I've ended up using the bltdpt trick to skip the first pixel.

To skip the last pixel I set the y-size to (dx no +1).

Setting the y-size seems equivalent to specifying the major increments, which makes sense.

I then have to skip single pixel lines.

Antiriad, your code seems to be skipping an entire row which works if you are drawing with the ONEDOT mode but isn't what I'm after.
Jobbo is offline  
Old 27 December 2020, 20:48   #17
Antiriad_UK
OCS forever!

Antiriad_UK's Avatar
 
Join Date: Mar 2019
Location: Birmingham, UK
Posts: 335
Quote:
Originally Posted by Jobbo View Post
Thanks for the responses.
Antiriad, your code seems to be skipping an entire row which works if you are drawing with the ONEDOT mode but isn't what I'm after.


Let us know how you get on
Antiriad_UK is offline  
Old 28 December 2020, 17:44   #18
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
For anyone interested, this is how I'm getting on:



Figuring out some bugs in my poly vert/face/edge/neighbor generation.
Attached Thumbnails
Click image for larger version

Name:	origami.jpg
Views:	277
Size:	56.0 KB
ID:	70091  
Jobbo is offline  
Old 29 December 2020, 06:11   #19
Jobbo
Registered User

Jobbo's Avatar
 
Join Date: Jun 2020
Location: Lexington, MA
Posts: 83
This is how it's looking after a lot of tricky changes to when and how each line is drawn.

It's a lot more trouble than it's probably worth but I don't think you could pull off a 4 bitplane poly shape this large with the blitter doing the fill.

It's running at 50hz with a screen size of 320x256.

[ Show youtube player ]

Last edited by Jobbo; 29 December 2020 at 07:45.
Jobbo is offline  
Old 29 December 2020, 09:29   #20
ross
Defendit numerus

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 50
Posts: 2,997
I think it looks great .

Last edited by ross; 29 December 2020 at 09:49.
ross is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Looking for mod player with GFX demo effects lifeschool request.Apps 14 18 April 2018 20:49
Demos with music or sound effects in time with graphic effects mark_k request.Demos 7 07 December 2016 21:23
Looking for old, long HAM demo Foebane request.Demos 10 08 November 2014 12:26
Oldschool demo effects on websites! Kodoichi Amiga scene 3 08 November 2006 20:01
HAM Demo Frazor request.Demos 2 06 August 2003 15:36

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 13:19.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, vBulletin Solutions Inc.
Page generated in 0.13419 seconds with 14 queries