Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: Dr_D on January 25, 2010
-
Hey guys. I was just messing around, and I'm having some problems here. Can anyone spot what I'm doing wrong? It could use tons and tons of optimizations, but I can't get the texture coords working properly now... I don't know what I've done. Thanks! :)
#include "fbgfx.bi"
type vec2f
as single x, y
end type
type vec3f
as single x, y, z
end type
type trgb
as uinteger r,g,b
end type
const as integer scr_w = 640
const as integer scr_h = 480
screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY
declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byval p1 as vec3f, byval t1 as vec2f, byval cl1 as trgb, byval p2 as vec3f, byval t2 as vec2f, byval cl2 as trgb, byval p3 as vec3f, byval t3 as vec2f, byval cl3 as trgb, byref texture as FB.IMAGE ptr )
dim as FB.IMAGE ptr image = imagecreate( 256, 256 )
if bload( "rock.bmp", image) <> 0 then
for y as integer = 0 to 255
for x as integer = 0 to 255
dim as integer rgbc = (x and y)
pset image,(x,y), rgb( rgbc, rgbc, rgbc )
next
next
end if
dim as vec3f p1, p2, p3
dim as vec2f t1, t2, t3
dim as trgb c1, c2, c3
t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )
c1= type(255,0,0)
c2= type(0,255,0)
c3= type(0,0,255)
do
dim as double ttime = timer
p1 = type( 320+350*sin(ttime), 240+350*cos(ttime), -10 )
p2 = type( 320+350*sin(ttime+1.5), 240+350*cos(ttime+1.5), -10 )
p3 = type( 320+350*sin(ttime+3.14), 240+350*cos(ttime+3.14), 0 )
screenlock
line(0,0)-(640,480),0,bf
tgpcTri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )
screensync
screenunlock
sleep 3,1
loop until inkey$ <> ""
sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byval p1 as vec3f, byval t1 as vec2f, byval cl1 as trgb, byval p2 as vec3f, byval t2 as vec2f, byval cl2 as trgb, byval p3 as vec3f, byval t3 as vec2f, byval cl3 as trgb, byref texture as FB.IMAGE ptr )
static as uinteger ptr dstptr
static as uinteger ptr srcptr
static as integer x1, x2, x3
static as integer y1, y2, y3
static as integer z1, z2, z3
static as integer u1, u2, u3
static as integer v1, v2, v3
static as integer r1, r2, r3
static as integer g1, g2, g3
static as integer b1, b2, b3
static as integer dw,dh,dbpp,dpitch
static as integer sw,sh,sbpp,spitch
static as integer scanlen, pu, pv
static as integer dx1, dx2, dx3
static as integer dy1, dy2, dy3
static as integer dz1, dz2, dz3
static as integer du1, du2, du3
static as integer dv1, dv2, dv3
static as integer dr1, dr2, dr3
static as integer dg1, dg2, dg3
static as integer db1, db2, db3
static as integer col, r, g, b
static as single sx, ex, sz, ez, su, eu, sv, ev, sr, er, sg, eg, sb, eb
static as single xd1, xd2, xd3, lx, rx, recz
static as single zd1, zd2, zd3, lz, rz, nz, zinc
static as single ud1, ud2, ud3, lu, ru, nu, uinc
static as single vd1, vd2, vd3, lv, rv, nv, vinc
static as single rd1, rd2, rd3, lr, rr, nr, rinc
static as single bd1, bd2, bd3, lb, rb, nb, binc
static as single gd1, gd2, gd3, lg, rg, ng, ginc
if dst = 0 then
dstptr = screenptr
screeninfo dw, dh,, dbpp, dpitch
else
dstptr = cast (uinteger ptr, dst+1 )
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if
srcptr = cast (uinteger ptr, texture+1 )
sw = texture->width
sh = texture->height
sbpp = texture->bpp
spitch = texture->pitch
x1 = p1.x
x2 = p2.x
x3 = p3.x
y1 = p1.y
y2 = p2.y
y3 = p3.y
z1 = p1.z
z2 = p2.z
z3 = p3.z
u1 = t1.x
u2 = t2.x
u3 = t3.x
v1 = t1.y
v2 = t2.y
v3 = t3.y
r1 = cl1.r
r2 = cl2.r
r3 = cl3.r
g1 = cl1.g
g2 = cl2.g
g3 = cl3.g
b1 = cl1.b
b2 = cl2.b
b3 = cl3.b
if y2 < y1 then
swap x1, x2
swap y1, y2
swap z1, z2
swap u1, u2
swap v1, v2
swap r1, r2
swap g1, g2
swap b1, b2
end if
if y3 < y1 then
swap x3, x1
swap y3, y1
swap z3, z1
swap u3, u1
swap v3, v1
swap r3, r1
swap g3, g1
swap b3, b1
end if
if y3 < y2 then
swap x3, x2
swap y3, y2
swap z3, z2
swap u3, u2
swap v3, v2
swap r3, r2
swap g3, g2
swap b3, b2
end if
dx1 = x2 - x1
dy1 = y2 - y1
dz1 = z2 - z1
du1 = u2 - u1
dv1 = v2 - v1
dr1 = r2 - r1
dg1 = g2 - g1
db1 = b2 - b1
if dy1 <> 0 then
xd1 = dx1 / dy1
zd1 = dz1 / dy1
ud1 = du1 / dy1
vd1 = dv1 / dy1
rd1 = dr1 / dy1
gd1 = dg1 / dy1
bd1 = db1 / dy1
else
xd1 = 0
zd1 = 0
ud1 = 0
vd1 = 0
rd1 = 0
gd1 = 0
bd1 = 0
end if
dx2 = x3 - x2
dy2 = y3 - y2
dz2 = z3 - z2
du2 = u3 - u2
dv2 = v3 - v2
dr2 = r3 - r2
dg2 = g3 - g2
db2 = b3 - b2
if dy2 <> 0 then
xd2 = dx2 / dy2
zd2 = dz2 / dy2
ud2 = du2 / dy2
vd2 = dv2 / dy2
rd2 = dr2 / dy2
gd2 = dg2 / dy2
bd2 = db2 / dy2
else
xd2 = 0
zd2 = 0
ud2 = 0
vd2 = 0
rd2 = 0
gd2 = 0
bd2 = 0
end if
dx3 = x1 - x3
dy3 = y1 - y3
dz3 = z1 - z3
du3 = u1 - u3
dv3 = v1 - v3
dr3 = r1 - r3
dg3 = g1 - g3
db3 = b1 - b3
if dy3 <> 0 then
xd3 = dx3 / dy3
zd3 = dz3 / dy3
ud3 = du3 / dy3
vd3 = dv3 / dy3
rd3 = dr3 / dy3
gd3 = dg3 / dy3
bd3 = db3 / dy3
else
xd3 = 0
zd3 = 0
ud3 = 0
vd3 = 0
rd3 = 0
gd3 = 0
bd3 = 0
end if
lx = x1
rx = x1
lz = z1
rz = z1
lu = u1
ru = u1
lv = v1
rv = v1
lr = r1
rr = r1
lg = g1
rg = g1
lb = b1
rb = b1
for y as integer = y1 to y2 - 1
if y>-1 and y<dh then
sx = lx
ex = rx
su = lu
eu = ru
sv = lv
ev = rv
sz = lz
ez = rz
sr = lr
er = rr
sg = lg
eg = rg
sb = lb
eb = rb
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
swap sr, er
swap sg, eg
swap sb, eb
end if
scanlen = (ex-sx)
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen
rinc = (er-sr) / scanlen
ginc = (eg-sg) / scanlen
binc = (eb-sb) / scanlen
nu = su/sz
nv = sv/sz
nz = 1.0/sz
nr = sr
ng = sg
nb = sb
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1.0/nz
pu = abs(nu*recz) MOD sw
pv = abs(nv*recz) MOD sh
col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
r+=(nr)
if r<0 then
r = 0
elseif r>255 then
r = 255
end if
g+=(ng)
if g<0 then
g = 0
elseif g>255 then
g = 255
end if
b+=(nb)
if b<0 then
b = 0
elseif b>255 then
b = 255
end if
*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
end if
nu+=uinc
nv+=vinc
nz+=zinc
nr+=rinc
ng+=ginc
nb+=binc
next
end if
lx += xd1
rx += xd3
lu += ud1
ru += ud3
lv += vd1
rv += vd3
lz += zd1
rz += zd3
lr += rd1
rr += rd3
lg += gd1
rg += gd3
lb += bd1
rb += bd3
next
lx = x2
lz = z2
lu = u2
lv = v2
lr = r2
lg = g2
lb = b2
for y as integer = y2 to y3
if y>-1 and y<dh then
sx = lx
ex = rx
su = lu
eu = ru
sv = lv
ev = rv
sz = lz
ez = rz
sr = lr
er = rr
sg = lg
eg = rg
sb = lb
eb = rb
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
swap sr, er
swap sg, eg
swap sb, eb
end if
scanlen = (ex-sx)+1
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen
rinc = (er-sr) / scanlen
ginc = (eg-sg) / scanlen
binc = (eb-sb) / scanlen
nu = su/sz
nv = sv/sz
nz = 1.0/sz
nr = sr
ng = sg
nb = sb
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1.0/nz
pu = abs(nu*recz) MOD sw
pv = abs(nv*recz) MOD sh
col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
r+=(nr)
if r<0 then
r = 0
elseif r>255 then
r = 255
end if
g+=(ng)
if g<0 then
g = 0
elseif g>255 then
g = 255
end if
b+=(nb)
if b<0 then
b = 0
elseif b>255 then
b = 255
end if
*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
end if
nu+=uinc
nv+=vinc
nz+=zinc
nr+=rinc
ng+=ginc
nb+=binc
next
end if
lx += xd2
rx += xd3
lu += ud2
ru += ud3
lv += vd2
rv += vd3
lz += zd2
rz += zd3
lr += rd2
rr += rd3
lg += gd2
rg += gd3
lb += bd2
rb += bd3
next
end sub
-
Hi Dr_D,
I can't really see what your code is doing cos the forum has stuck it in a box the size of a postage stamp! :-\
The idea of perspective correct mapping is you interpolate u/z, v/z and 1/z and for each pixel you divide the u/z by 1/z to get u, and v/z by 1/z to get v.
So there are a few things to check - make sure you are making u/z, v/z, 1/z properly at the corners and edges, and make sure all your increments have enough precision (floats should be ok). If you can get that working then cool.
If you're still having trouble, let us know!
Jim
-
Thanks man... I actually had it working a while back, like shortly after fb first came around, but I've been through several computers and a hdd crash since then. This is good practice anyway. ;)
-
I don't understand what's wrong here... Can anyone spot what the problem(s) might be? The interpolation across z, u and v is obviously wrong... Thanks again guys. :)
#include "fbgfx.bi"
type vec2f
as single x, y
end type
type vec3f
as single x, y, z
end type
type trgb
as uinteger r,g,b
end type
type tgpcTri_struct
dim as single x1, y1, z1
dim as single x2, y2, z2
dim as single x3, y3, z3
dim as single u1, v1
dim as single u2, v2
dim as single u3, v3
dim as fb.image ptr texture
end type
const as integer scr_w = 640
const as integer scr_h = 480
declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )
screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY
dim as FB.IMAGE ptr image = imagecreate( 256, 256 )
if bload( "textures.bmp", image) <> 0 then
line image,(0,0)-(255,255),&hffffffff, bf
for i as integer = 0 to 255 step 16
'for x as integer = 0 to 255 step 16
line image,(0,i)-(255,i), &hff0000ff
line image,(i,0)-(i,255), &hff0000ff
'next
next
end if
dim as vec3f p1, p2, p3, p4
dim as vec2f t1, t2, t3, t4
dim as trgb c1, c2, c3, c4
t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )
t4 = type( 255, 0 )
c1= type(0,0,0)
c2= type(0,0,0)
c3= type(0,0,0)
c4= type(0,0,0)
dim as tgpcTri_struct tri1, tri2
tri1.texture = image
dim as double otime = timer
do
dim as single ttime = 5.53
p1 = type( 320f+250f*sin(ttime), 240f+250f*cos(ttime), 1 )
p2 = type( 320f+250f*sin(ttime+1.5), 240f+250f*cos(ttime+1.5), 1 )
p3 = type( 320f+75f*sin(ttime+3.14), 240f+75f*cos(ttime+3.14), 10 )
p4 = type( 320f+75f*sin(ttime+3.14+1.5), 240f+75f*cos(ttime+3.14+1.5), 10 )
tri1.x1 = p1.x
tri1.x2 = p2.x
tri1.x3 = p3.x
tri1.y1 = p1.y
tri1.y2 = p2.y
tri1.y3 = p3.y
tri1.z1 = p1.z
tri1.z2 = p2.z
tri1.z3 = p3.z
tri1.u1 = t1.x
tri1.u2 = t2.x
tri1.u3 = t3.x
tri1.v1 = t1.y
tri1.v2 = t2.y
tri1.v3 = t3.y
tri2.x1 = p3.x
tri2.x2 = p4.x
tri2.x3 = p1.x
tri2.y1 = p3.y
tri2.y2 = p4.y
tri2.y3 = p1.y
tri2.z1 = p3.z
tri2.z2 = p4.z
tri2.z3 = p1.z
tri2.u1 = t3.x
tri2.u2 = t4.x
tri2.u3 = t1.x
tri2.v1 = t3.y
tri2.v2 = t4.y
tri2.v3 = t1.y
screenlock
line(0,0)-(640,480),0,bf
tgpctri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )
tgpctri(0, p3, t3, c3, p4, t4, c4, p1, t1, c1, image )
locate 1,1
print ttime
screensync
screenunlock
sleep 3,1
loop until inkey$ <> ""
sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )
dim as integer x1, x2, x3
dim as integer y1, y2, y3
dim as single z1, z2, z3
dim as single u1, u2, u3
dim as single v1, v2, v3
dim as integer r1, r2, r3
dim as integer g1, g2, g3
dim as integer b1, b2, b3
dim as uinteger ptr dstptr
dim as uinteger ptr srcptr
dim as integer dw,dh,dbpp,dpitch
dim as integer sw,sh,sbpp,spitch
dim as single scanlen
dim as integer pu, pv
dim as single dx1, dx2, dx3
dim as single dy1, dy2, dy3
dim as single dz1, dz2, dz3
dim as single du1, du2, du3
dim as single dv1, dv2, dv3
dim as single dr1, dr2, dr3
dim as single dg1, dg2, dg3
dim as single db1, db2, db3
dim as single sz, ez, su, eu, sv, ev, sr, er, sg, eg, sb, eb
dim as integer sx, ex
dim as single xd1, xd2, xd3, lx, rx
dim as single recz
dim as single zd1, zd2, zd3, lz, rz, nz, zinc
dim as single ud1, ud2, ud3, lu, ru, nu, uinc
dim as single vd1, vd2, vd3, lv, rv, nv, vinc
dim as single rd1, rd2, rd3, lr, rr, nr, rinc
dim as single bd1, bd2, bd3, lb, rb, nb, binc
dim as single gd1, gd2, gd3, lg, rg, ng, ginc
dim as single idz1, idz2, idz3
dim as integer col
dim as integer r, g, b
if dst = 0 then
dstptr = screenptr
screeninfo dw, dh,, dbpp, dpitch
else
dstptr = cast (uinteger ptr, dst+1 )
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if
srcptr = cast (uinteger ptr, texture+1 )
sw = texture->width
sh = texture->height
sbpp = texture->bpp
spitch = texture->pitch
x1 = int(p1.x)
x2 = int(p2.x)
x3 = int(p3.x)
y1 = int(p1.y)
y2 = int(p2.y)
y3 = int(p3.y)
z1 = p1.z
z2 = p2.z
z3 = p3.z
u1 = t1.x
u2 = t2.x
u3 = t3.x
v1 = t1.y
v2 = t2.y
v3 = t3.y
r1 = cl1.r
r2 = cl2.r
r3 = cl3.r
g1 = cl1.g
g2 = cl2.g
g3 = cl3.g
b1 = cl1.b
b2 = cl2.b
b3 = cl3.b
if y2 < y1 then
swap x1, x2
swap y1, y2
swap z1, z2
swap u1, u2
swap v1, v2
swap r1, r2
swap g1, g2
swap b1, b2
end if
if y3 < y1 then
swap x3, x1
swap y3, y1
swap z3, z1
swap u3, u1
swap v3, v1
swap r3, r1
swap g3, g1
swap b3, b1
end if
if y3 < y2 then
swap x3, x2
swap y3, y2
swap z3, z2
swap u3, u2
swap v3, v2
swap r3, r2
swap g3, g2
swap b3, b2
end if
idz1 = 1/z1
idz2 = 1/z2
idz3 = 1/z3
dx1 = x2 - x1
dy1 = y2 - y1
dz1 = idz2 - idz1 '((1/z2) - (1/z1))
du1 = (u2*idz2) - (u1*idz1)
dv1 = (v2*idz2) - (v1*idz1)
'dr1 = r2 - r1
'dg1 = g2 - g1
'db1 = b2 - b1
if dy1 <> 0 then
xd1 = dx1 / dy1
zd1 = dz1 / dy1
ud1 = du1 / dy1
vd1 = dv1 / dy1
'rd1 = dr1 / dy1
'gd1 = dg1 / dy1
'bd1 = db1 / dy1
else
xd1 = 0
zd1 = 0
ud1 = 0
vd1 = 0
'rd1 = 0
'gd1 = 0
'bd1 = 0
end if
dx2 = x3 - x2
dy2 = y3 - y2
dz2 = idz3-idz2 '((1/z3) - (1/z2))
du2 = (u3*idz3) - (u2*idz2)
dv2 = (v3*idz3) - (v2*idz2)
'dr2 = r3 - r2
'dg2 = g3 - g2
'db2 = b3 - b2
if dy2 <> 0 then
xd2 = dx2 / dy2
zd2 = dz2 / dy2
ud2 = du2 / dy2
vd2 = dv2 / dy2
'rd2 = dr2 / dy2
'gd2 = dg2 / dy2
'bd2 = db2 / dy2
else
xd2 = 0
zd2 = 0
ud2 = 0
vd2 = 0
'rd2 = 0
'gd2 = 0
'bd2 = 0
end if
dx3 = x1 - x3
dy3 = y1 - y3
dz3 = idz1-idz3'((1/z1) - (1/z3))
du3 = (u1*idz1) - (u3*idz3)
dv3 = (v1*idz1) - (v3*idz3)
'dr3 = r1 - r3
'dg3 = g1 - g3
'db3 = b1 - b3
if dy3 <> 0 then
xd3 = dx3 / dy3
zd3 = dz3 / dy3
ud3 = du3 / dy3
vd3 = dv3 / dy3
'rd3 = dr3 / dy3
'gd3 = dg3 / dy3
'bd3 = db3 / dy3
else
xd3 = 0
zd3 = 0
ud3 = 0
vd3 = 0
'rd3 = 0
'gd3 = 0
'bd3 = 0
end if
lx = x1
rx = x1
lz = idz1'1/z1
rz = idz1'1/z1
lu = u1*idz1'/z1
ru = u1*idz1'/z1
lv = v1*idz1'/z1
rv = v1*idz1'/z1
'lr = r1
'rr = r1
'lg = g1
'rg = g1
'lb = b1
'rb = b1
for y as integer = y1 to y2 - 1
if y>-1 and y<dh then
sx = lx
ex = rx
su = lu/lz
eu = ru/rz
sv = lv/lz
ev = rv/rz
sz = 1/lz
ez = 1/rz
'sr = lr
'er = rr
'sg = lg
'eg = rg
'sb = lb
'eb = rb
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
'swap sr, er
'swap sg, eg
'swap sb, eb
end if
nz = 1/sz
nu = su*nz
nv = sv*nz
'nr = sr
'ng = sg
'nb = sb
scanlen = (ex-sx)'+1
uinc = ((eu/ez)-(su/sz)) / scanlen
vinc = ((ev/ez)-(sv/sz)) / scanlen
zinc = ((1/ez)-(1/sz)) / scanlen
'rinc = (er-sr) / scanlen
'ginc = (eg-sg) / scanlen
'binc = (eb-sb) / scanlen
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1/nz
pu = abs(nu*recz)' MOD sw
pv = abs(nv*recz)' MOD sh
col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
'col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
'pset(x,y),rgb(r,g,b)
end if
nu+=uinc
nv+=vinc
nz+=zinc
'nr+=rinc
'ng+=ginc
'nb+=binc
next
end if
lx += xd1
rx += xd3
lu += ud1
ru += ud3
lv += vd1
rv += vd3
lz += zd1
rz += zd3
'lr += rd1
'rr += rd3
'lg += gd1
'rg += gd3
'lb += bd1
'rb += bd3
next
lx = x2
lz = idz2 '1/z2
lu = u2*idz2'/z2
lv = v2*idz2'/z2
'lr = r2
'lg = g2
'lb = b2
'exit sub
for y as integer = y2 to y3
if y>-1 and y<dh then
sx = lx
ex = rx
sz = 1/lz
ez = 1/rz
su = lu/lz
eu = ru/rz
sv = lv/lz
ev = rv/rz
'sr = lr
'er = rr
'sg = lg
'eg = rg
'sb = lb
'eb = rb
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
'swap sr, er
'swap sg, eg
'swap sb, eb
end if
nz = 1/sz
nu = su*nz
nv = sv*nz
'nr = sr
'ng = sg
'nb = sb
scanlen = (ex-sx)'+1
uinc = ((eu/ez)-(su/sz)) / scanlen
vinc = ((ev/ez)-(sv/sz)) / scanlen
zinc = ((1/ez)-(1/sz)) / scanlen
'rinc = (er-sr) / scanlen
'ginc = (eg-sg) / scanlen
'binc = (eb-sb) / scanlen
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1/nz
pu = abs(nu*recz)' MOD sw
pv = abs(nv*recz)' MOD sh
col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
'col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
'pset(x,y),rgb(r,g,b)
end if
nu+=uinc
nv+=vinc
nz+=zinc
'nr+=rinc
'ng+=ginc
'nb+=binc
next
end if
lx += xd2
rx += xd3
lu += ud2
ru += ud3
lv += vd2
rv += vd3
lz += zd2
rz += zd3
'lr += rd2
'rr += rd3
'lg += gd2
'rg += gd3
'lb += bd2
'rb += bd3
next
end sub
-
It looks like you're making this way too complicated, you've got far too many divide by z going on. I take it you've got affine mapping working so go back to that and use that as a starting point.
You only need to divide u and v by z and divide 1 by z for each vertex right at the start of your tri sub.
Then inside your inner loop you multiply the interpolated u/z and v/z values by the reciprocal of the interpolated 1/z value.
-
A general suggestion:
Use a single structure holding all vertex-attributes:
type Vertex
as single x, y, z
as single u, v
end type
Send pointers of vertices to your triangle-filler.
When swapping two vertices you can simply swap their pointers instead of actually moving data around:
if v2->y < v1->y then
swap v1, v2
end if
If your triangles have constant winding you can even send a list of vertex-pointers.
Now just find the index of the topmost vertex from the list.
All bigger indices are on the left side of the triangle and the smaller indices on the right.
There's no reason to swap anything.
-
Thanks for the suggestions. This is all based off code from relsoft's tutorial, but I haven't been able to get the perspective mapping to work properly. I'm going to try again and again until i get it right. ;)
-
Sorry to reply again so soon... I'm really not trying to drive you guys nuts. :p Anyway, I really don't understand what I'm doing wrong though... I removed the tries for color interpolation for now, and cleaned it up a bit because if I can get the perspective texture correction down, the colors will be easy using the same method. Also, I renamed a few vars to something more understandable. If I read everything I've looked at right, this should be working... so I must not have read it right. Thanks for taking time to look at it. :)
#include "fbgfx.bi"
type vec2f
as single x, y
end type
type vec3f
as single x, y, z
end type
type trgb
as uinteger r,g,b
end type
type tgpcTri_struct
dim as single x1, y1, z1
dim as single x2, y2, z2
dim as single x3, y3, z3
dim as single u1, v1
dim as single u2, v2
dim as single u3, v3
dim as fb.image ptr texture
end type
const as integer scr_w = 640
const as integer scr_h = 480
declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )
screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY
dim as FB.IMAGE ptr image = imagecreate( 256, 256 )
if bload( "texture.bmp", image) <> 0 then
line image,(0,0)-(255,255),&hffffffff, bf
for i as integer = 0 to 255 step 16
line image,(0,i)-(255,i), &hff0000ff
line image,(i,0)-(i,255), &hff0000ff
next
end if
dim as vec3f p1, p2, p3, p4
dim as vec2f t1, t2, t3, t4
dim as trgb c1, c2, c3, c4
t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )
t4 = type( 255, 0 )
c1= type(0,0,0)
c2= type(0,0,0)
c3= type(0,0,0)
c4= type(0,0,0)
dim as tgpcTri_struct tri1, tri2
tri1.texture = image
dim as double otime = timer
do
dim as single ttime = 5.53
p1 = type( 320f+250f*sin(ttime), 240f+250f*cos(ttime), 1 )
p2 = type( 320f+250f*sin(ttime+1.5), 240f+250f*cos(ttime+1.5), 1 )
p3 = type( 320f+75f*sin(ttime+3.14), 240f+75f*cos(ttime+3.14), 10 )
p4 = type( 320f+75f*sin(ttime+3.14+1.5), 240f+75f*cos(ttime+3.14+1.5), 10 )
tri1.x1 = p1.x
tri1.x2 = p2.x
tri1.x3 = p3.x
tri1.y1 = p1.y
tri1.y2 = p2.y
tri1.y3 = p3.y
tri1.z1 = p1.z
tri1.z2 = p2.z
tri1.z3 = p3.z
tri1.u1 = t1.x
tri1.u2 = t2.x
tri1.u3 = t3.x
tri1.v1 = t1.y
tri1.v2 = t2.y
tri1.v3 = t3.y
tri2.x1 = p3.x
tri2.x2 = p4.x
tri2.x3 = p1.x
tri2.y1 = p3.y
tri2.y2 = p4.y
tri2.y3 = p1.y
tri2.z1 = p3.z
tri2.z2 = p4.z
tri2.z3 = p1.z
tri2.u1 = t3.x
tri2.u2 = t4.x
tri2.u3 = t1.x
tri2.v1 = t3.y
tri2.v2 = t4.y
tri2.v3 = t1.y
screenlock
line(0,0)-(640,480),0,bf
tgpctri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )
tgpctri(0, p3, t3, c3, p4, t4, c4, p1, t1, c1, image )
screensync
screenunlock
sleep 3,1
loop until inkey$ <> ""
sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )
dim as integer x1, x2, x3
dim as integer y1, y2, y3
dim as single z1, z2, z3
dim as single u1, u2, u3
dim as single v1, v2, v3
dim as uinteger ptr dstptr
dim as uinteger ptr srcptr
dim as integer dw,dh,dbpp,dpitch
dim as integer sw,sh,sbpp,spitch
dim as integer scanlen
dim as integer pu, pv
dim as single xlen1, xlen2, xlen3
dim as single ylen1, ylen2, ylen3
dim as single zlen1, zlen2, zlen3
dim as single ulen1, ulen2, ulen3
dim as single vlen1, vlen2, vlen3
dim as single sz, ez, su, eu, sv, ev
dim as integer sx, ex
dim as single xd1, xd2, xd3, lx, rx
dim as single recz
dim as single zd1, zd2, zd3, lz, rz, nz, zinc
dim as single ud1, ud2, ud3, lu, ru, nu, uinc
dim as single vd1, vd2, vd3, lv, rv, nv, vinc
'reciprocal variables
dim as single u1dz1, u2dz2, u3dz3
dim as single v1dz1, v2dz2, v3dz3
dim as single idz1, idz2, idz3
dim as integer col
dim as integer r, g, b
if dst = 0 then
dstptr = screenptr
screeninfo dw, dh,, dbpp, dpitch
else
dstptr = cast (uinteger ptr, dst+1 )
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if
srcptr = cast (uinteger ptr, texture+1 )
sw = texture->width
sh = texture->height
sbpp = texture->bpp
spitch = texture->pitch
'assign vertices and uv coordinates to temp variables
x1 = int(p1.x)
x2 = int(p2.x)
x3 = int(p3.x)
y1 = int(p1.y)
y2 = int(p2.y)
y3 = int(p3.y)
z1 = p1.z
z2 = p2.z
z3 = p3.z
u1 = t1.x
u2 = t2.x
u3 = t3.x
v1 = t1.y
v2 = t2.y
v3 = t3.y
if y2 < y1 then
swap x1, x2
swap y1, y2
swap z1, z2
swap u1, u2
swap v1, v2
end if
if y3 < y1 then
swap x3, x1
swap y3, y1
swap z3, z1
swap u3, u1
swap v3, v1
end if
if y3 < y2 then
swap x3, x2
swap y3, y2
swap z3, z2
swap u3, u2
swap v3, v2
end if
'reciprocals for each z... trying to speed it up a bit without confusing myself any more
idz1 = 1/z1
idz2 = 1/z2
idz3 = 1/z3
'uv's divided by z
u1dz1 = u1/z1
u2dz2 = u2/z2
u3dz3 = u3/z3
v1dz1 = v1/z1
v2dz2 = v2/z2
v3dz3 = v3/z3
'calculate the interpolation for the top left leg
'of course the actual loops will change on flat bottom || top triangles
'i think that's my problem with this whole method
xlen1 = x2 - x1
ylen1 = y2 - y1
zlen1 = idz2 - idz1
ulen1 = u2dz2 - u1dz1
vlen1 = v2dz2 - v1dz1
if ylen1 <> 0 then
xd1 = xlen1 / ylen1
zd1 = zlen1 / ylen1
ud1 = ulen1 / ylen1
vd1 = vlen1 / ylen1
else
xd1 = 0
zd1 = 0
ud1 = 0
vd1 = 0
end if
'calculate the interpolation for the right leg
xlen2 = x3 - x2
ylen2 = y3 - y2
zlen2 = idz3 - idz2
ulen2 = u3dz3 - u2dz2
vlen2 = v3dz3 - v2dz2
if ylen2 <> 0 then
xd2 = xlen2 / ylen2
zd2 = zlen2 / ylen2
ud2 = ulen2 / ylen2
vd2 = vlen2 / ylen2
else
xd2 = 0
zd2 = 0
ud2 = 0
vd2 = 0
end if
'calculate the interpolation for the bottom left leg
xlen3 = x1 - x3
ylen3 = y1 - y3
zlen3 = idz1 - idz3
ulen3 = u1dz1 - u3dz3
vlen3 = v1dz1 - v3dz3
if ylen3 <> 0 then
xd3 = xlen3 / ylen3
zd3 = zlen3 / ylen3
ud3 = ulen3 / ylen3
vd3 = vlen3 / ylen3
else
xd3 = 0
zd3 = 0
ud3 = 0
vd3 = 0
end if
'enter the actual rendering loops finally...
'everything starts at pointA, the top(and left) of the triangle
lx = x1
rx = x1
lz = idz1
rz = idz1
lu = u1dz1
ru = u1dz1
lv = v1dz1
rv = v1dz1
for y as integer = y1 to y2 - 1
if y>-1 and y<dh then
sx = lx
ex = rx
su = lu
eu = ru
sv = lv
ev = rv
sz = lz
ez = rz
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
end if
nz = sz
nu = su
nv = sv
scanlen = ex-sx
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1/nz
pu = abs(nu*recz)
pv = abs(nv*recz)
'col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
'*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
pset(x,y),rgb(r,g,b)
end if
nu+=uinc
nv+=vinc
nz+=zinc
next
end if
lx += xd1
rx += xd3
lu += ud1
ru += ud3
lv += vd1
rv += vd3
lz += zd1
rz += zd3
next
'bottom half
'set the left side to pointB
lx = x2
lz = idz2
lu = u2dz2
lv = v2dz2
for y as integer = y2 to y3
if y>-1 and y<dh then
sx = lx
ex = rx
sz = lz
ez = rz
su = lu
eu = ru
sv = lv
ev = rv
if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
end if
nz = sz
nu = su
nv = sv
scanlen = ex-sx
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen
for x as integer = sx to ex
if x>-1 and x<dw then
recz = 1/nz
pu = abs(nu*recz)
pv = abs(nv*recz)
'col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col) and 255
'*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
pset(x,y),rgb(r,g,b)
end if
nu+=uinc
nv+=vinc
nz+=zinc
next
end if
lx += xd2
rx += xd3
lu += ud2
ru += ud3
lv += vd2
rv += vd3
lz += zd2
rz += zd3
next
end sub
-
lol, n/m... that last one works. sorry guys, i found my mistake now. it can't just accept a random value for z, it actually needs the correct projection values. :updance:
-
I take it you're using abs to stop your tex coords going out of range, there is a better way that also allows for texture wrapping.
Hint: It requires the texture sizes to be powers of 2.
-
Heh, yeah, I started AND'ing the coords instead. :p to make it compatible with what i want to use it for, it' sgoping to have to work with negative coordinates as well, without mirroring it. That doesn't really matter right now though. I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
-
ANDing deals with negative values fine.
Sub pixel, just realise that the first pixel of your scanline is often not actually the start of your scanline, there is a small fraction of a pixel before it that you're missing out and therefore a small part of your texture is missed out too, that goes for the end of the scanline and also for the top and bottom of your triangles.
Make sure you understand your filling convention too, along with how the floats are being rounded for the start and end of inner and outer loops and for tex coords inside the inner loop.
And have a think about your deltas.
-
Truncating all your x,y floats towards 0 when rendering is enough to ensure you never get cracking, though Stonemonkey is bang on to say that that's not perfect - it's very good though. There's no need to perspective correct your r,g,b imho, there's enough error in the fact your using Gouraud and the RGB colour-space to make it irrelevant, just perspective correct the u,v, which is really important.
Jim
-
I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
I once posted an image here (http://www.dbfinteractive.com/forum/index.php/topic,3445.msg49641.html#msg49641) which shows the gaps between the interpolated edges and the drawn pixels.
It assumes rounding floating-point coordinates to next bigger integers.
-
I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
I once posted an image here (http://www.dbfinteractive.com/forum/index.php/topic,3445.msg49641.html#msg49641) which shows the gaps between the interpolated edges and the drawn pixels.
It assumes rounding floating-point coordinates to next bigger integers.
Good pic, I tend to round down but whichever way you decide to go, pick a point on the pixel and use that to determiine if a pixel is inside or outside the triangle, don't use the whole pixel area.
It's also possible to set the rounding mode of the CPU in freebasic with a bit of inline asm. I found that handy since the rounding standard of NEAREST but xx.5 is rounded up or down depending on whether xx is even or odd to be a bit of a pain.
-
well, i've been testing a bit more, but it's still misfiring. i've been trying to follow this (http://"http://www.tutorialized.com/view/tutorial/Sub-pixel-accuracy/42327") tutorial, but it doesn't seem to be very thorough. it seems like it's close at times, but then you can see how it goes wild. if anyone could steer my nose the proper way i'd appreciate it. thanks. ;)
#include "fbgfx.bi"
type vec2f
as single x, y
declare constructor()
declare constructor( byval x as single, byval y as single )
declare sub rotate( byval rad as single )
declare sub translate( byval x as single, byval y as single )
end type
declare sub Triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )
declare sub bpset( byval x as integer, byval y as integer, byval col as uinteger )
const as integer sw = 1024
const as integer sh = 768
const as integer pix_size = 10
const as integer tri_size = 128\pix_size
const as integer swc = (sw\pix_size)\2, shc = (sh\pix_size)\2
screenres sw,sh,32
dim as double ttime = timer
dim as single rad
do
ttime = timer
rad = sin(ttime/10)
dim as vec2f p1, p2, p3
p1.translate(-tri_size, tri_size)
p2.translate(-tri_size, -tri_size)
p3.translate(tri_size,-tri_size)
p1.rotate(rad)
p2.rotate(rad)
p3.rotate(rad)
p1.translate(swc,shc)
p2.translate(swc,shc)
p3.translate(swc,shc)
screenlock
cls
for y as integer = 0 to shc*2
for x as integer = 0 to swc*2
line(x*pix_size, y*pix_size)-step(pix_size-1, pix_size-1),&hff333333,b
next
next
triangle( 0, p1, p2, p3, &hff0000ff )
screensync
screenunlock
sleep 3,1
loop until multikey(FB.SC_ESCAPE)
constructor vec2f()
end constructor
constructor vec2f( byval x as single, byval y as single )
this.x = x
this.y = y
end constructor
sub vec2f.rotate( byval rad as single )
dim as vec2f t
t.x = this.x * cos(rad) - this.y * sin(rad)
t.y = this.y * cos(rad) + this.x * sin(rad)
this = t
end sub
sub vec2f.translate( byval x as single, byval y as single )
this.x += x
this.y += y
end sub
function sub_pix( byval inval as single ) as single
dim as single retval
dim as const single half = 0.5
asm
fld dword ptr[inval]
fld dword ptr[inval]
fsub dword ptr [half]
frndint
fsubp st(1), st
fld1
fsubrp st(1), st
fstp dword ptr[retval]
end asm
return retval
end function
sub Triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )
dim as uinteger ptr dstptr, dptr1
dim as integer x,y
dim as integer dw,dh, dpitch, dbpp
dim as single dx1,dx2,dx3,dy1,dy2,dy3,sx,ex
dim as single d1, d2, d3, lx, rx
if dst = 0 then
dstptr = screenptr
screeninfo dw,dh,,dbpp, dpitch
else
dstptr = cast( uinteger ptr, dst + 1)
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if
'reverse for normal coordinate system
dim as single y1 = (dh\pix_size) - p1.y
dim as single y2 = (dh\pix_size) - p2.y
dim as single y3 = (dh\pix_size) - p3.y
dim as single x1 = p1.x
dim as single x2 = p2.x
dim as single x3 = p3.x
if y2 < y1 then
swap y1, y2
swap x1, x2
end if
if y3 < y1 then
swap y3, y1
swap x3, x1
end if
if y3 < y2 then
swap y3, y2
swap x3, x2
end if
dx1 = x2 - x1
dy1 = y2 - y1
if dy1 <> 0 then
d1 = dx1 / dy1
else
d1 = 0
end if
dx2 = x3 - x2
dy2 = y3 - y2
if dy2 <> 0 then
d2 = dx2 / dy2
else
d2 = 0
end if
dx3 = x1 - x3
dy3 = y1 - y3
if dy3 <> 0 then
d3 = dx3 / dy3
else
d3 = 0
end if
'lx = x1
'rx = x1
lx = x1' + (d1*sub_pix(y1))
rx = x1' + (d3*sub_pix(y3))
y = y1
while y<y2
if y>-1 and y<dh then
sx = lx + (d1*sub_pix(y1))
ex = rx + (d3*sub_pix(y3))
if sx>ex then
swap sx,ex
end if
if sx<0 then
sx = 0
end if
if ex>dw-1 then
ex=dw-1
end if
x = sx
'dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + x * dbpp)
while x<ex
'*dptr1 = col
'dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
x+=1
wend
end if
lx += d1
rx += d3
y+=1
wend
lx = x2 + (d2*sub_pix(y2))
'rx = constant slope
y = y2
while y<=y3
if y>-1 and y<dh then
sx = lx + (d2*sub_pix(y2))
ex = rx + (d3*sub_pix(y3))
if sx>ex then
swap sx,ex
end if
if sx<0 then
sx = 0
end if
if ex>dw-1 then
ex=dw-1
end if
x = sx
'dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + x * dbpp)
while x<ex
'*dptr1 = col
'dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
x+=1
wend
end if
lx += d2
rx += d3
y+=1
wend
end sub
-
y = y1
while y<y2
sx = lx + (d1*sub_pix(y1))
ex = rx + (d3*sub_pix(y3))
You're now re-applying the subpixel correction every scanline.
You just have to do it once to compensate the gap between "y1" and "y" (and again for the other edge when y reaches y2).
What you do every scanline is the texel-correction to compensate the gap between "sx" and "lx":
fracX= sub_pix(leftX);
u = leftU + (deltaU * fracX);
v = leftV + (deltaV * fracX);
(deltaU and deltaV are the deltas across the scanline)
-
well, i was doing the calculations right before the scanline loops start, one for lx and rx at the top loop, and one only for lx at the bottom loop, but it still didn't seem to work. the code here is just posting it out of frustration after testing several different methods. :\
-
Here's a small excerpt from an affine texture-mapper I wrote in C somewhen in the mid 90's.
Input for the polyfiller is an array of vertices:
struct Vertex
{
float x,y;
float u,v;
};
You would typically work with fixed-point coordinates in screen-space but the code looks a bit less obscure with floats.
Starting at the top-most vertex "topVtx" I track along the left and right edge.
Since all polygons are defined in counter-clockwise order, topVtx[1] is to the left and topVtx[-1] is to the right.
Imagine some additional code to make sure that vertices [-1] and [+1] actually exist.
ceil() rounds to the next bigger integer but can be replaced with any other rounding-function.
Left side:
leftVtx = topVtx;
// deltas along left edge
invHeight= 1.0 / (leftVtx[1].y - leftVtx[0].y);
leftDx = (leftVtx[1].x - leftVtx[0].x) * invHeight;
leftDu = (leftVtx[1].u - leftVtx[0].u) * invHeight;
leftDv = (leftVtx[1].v - leftVtx[0].v) * invHeight;
// subpixel correction
// this is the difference between the vertex' y-coordinate and the integer scanline
diffY = ceil(leftVtx[0].y) - leftVtx[0].y;
leftX = leftVtx[0].x + diffY * leftDx;
leftU = leftVtx[0].u + diffY * leftDu;
leftV = leftVtx[0].v + diffY * leftDv;
// proceed to next edge
leftVtx++;
(you can skip this calculation if both vertices are in the same scanline)
The same is done for the right edge but as the deltas across the scanline are constant, you just need to keep track of the x-position:
rightVtx = topVtx;
invHeight= 1.0 / (rightVtx[-1].y - rightVtx[0].y);
rightDx = (rightVtx[-1].x - rightVtx[0].x) * invHeight;
diffY = ceil(rightVtx[0].y) - rightVtx[0].y;
rightX = rightVtx[0].x + diffY * rightDx;
rightVtx++;
Now draw vertical scanlines until either rightVtx.y or leftVtx.y is reached.
Here each scanline has an interpolated floating-point starting-position so the difference between leftX and the integer pixel position needs to be fixed:
// integer pixel-positions of scanline-start and -end
x1 = ceil(leftX);
x2 = ceil(rightX);
// subtexel correction
diffX = x1 - leftX;
u = leftU + diffX * deltaU;
v = leftV + diffX * deltaV;
// fill scanline
for (x=x1; x<x2; x++)
{
...
}
Afterwards keep track of the edges:
// left side
leftX += leftDx;
leftU += leftDu;
leftV += leftDv;
// right side
rightX += rightDx;
As I process clipped polygons (resulting in arbitrary convex polygons) I don't use the typical top-half/bottom-half triangle approach but recalculate the deltas for left and right on-the-fly whenever the scanline-counter reaches one of them.
-
Man, this is crazy... Mine still doesn't work properly. I understand what's going on, or so I think, but it makes no sense for it to do this... it almost works, damn it. Can you see what's going on? I even switched to use reciprocals for the slope calculations, as yours does. It wont matter right now, but it's a nice optimization for the one with actual texturing and shading. Thanks again for the help. ;)
function sub_pix( byval inval as single ) as single
return 1f - (ceil(inval) - inval)
end function
sub triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )
dim as uinteger ptr dstptr, dptr1
dim as integer sx, ex
dim as integer dw,dh, dpitch, dbpp
dim as single d1, d2, d3, lx, rx, invheight
if dst = 0 then
dstptr = screenptr
screeninfo dw,dh,,dbpp, dpitch
else
dstptr = cast( uinteger ptr, dst + 1)
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if
'reverse for normal coordinate system
dim as single y1 = (dh\pix_size) - p1.y
dim as single y2 = (dh\pix_size) - p2.y
dim as single y3 = (dh\pix_size) - p3.y
dim as single x1 = p1.x
dim as single x2 = p2.x
dim as single x3 = p3.x
if y2 < y1 then
swap y1, y2
swap x1, x2
end if
if y3 < y1 then
swap y3, y1
swap x3, x1
end if
if y3 < y2 then
swap y3, y2
swap x3, x2
end if
if y2>y1 then
invheight = 1f/(y2-y1)
else
invheight = 1f
end if
d1 = (x2 - x1) * invheight
if y3<>y2 then
invheight = 1f/(y3-y2)
else
invheight = 1f
end if
d2 = (x3 - x2) * invheight
if y1<>y3 then
invheight = 1f/(y1-y3)
else
invheight = 1f
end if
d3 = (x1 - x3) * invheight
lx = x1 + (d1*sub_pix(y1))
rx = x1 + (d3*sub_pix(y3))
locate 1,1
print d1, d1, d3
for y as integer = y1 to y2-1
if y>-1 and y<dh then
sx = ceil(lx)
ex = ceil(rx)
if sx>ex then
swap sx,ex
end if
if sx<0 then
sx = 0
end if
if ex>dw-1 then
ex=dw-1
end if
dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + sx * dbpp)
for x as integer = sx to ex
'*dptr1 = col
dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
next
end if
lx += d1
rx += d3
'y+=1
next
lx = x2 + (d2*sub_pix(y2))
'rx = constant slope
for y as integer = y2 to y3
if y>-1 and y<dh then
sx = ceil(lx)
ex = ceil(rx)
if sx>ex then
swap sx,ex
end if
if sx<0 then
sx = 0
end if
if ex>dw-1 then
ex=dw-1
end if
'x = sx
dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + sx * dbpp)
for x as integer = sx to ex
'*dptr1 = col
dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
next
end if
lx += d2
rx += d3
next
end sub
-
Are you sure that this
for y as integer = y1performs the same rounding as you imply here:
1 - (ceil(inval) - inval)?
"sub_pix" won't work for "ceil(i)=i", eg. i= 5.0.
-
Yeah, that rounding would be different since fb's integer rounding by default only scales up when it's >= .5. I've modified that bit to use the ceil function, making it consistent across all variables. I've also used ceil for converting the y loops to integer, but it's still acting weird. I have to find where that dn calculation is drifting to infinity... I'm sure that's it, it so close now. :crutches:
-
fb's integer rounding by default only scales up when it's >= .5
No,
5.5 will round up to 6
4.5 will round down to 4
Jim
-
Damn, I never noticed that.. I guess that's what Stonemonkey mentioned. It makes sense now. :p
-
Truncating all your x,y floats towards 0 when rendering is enough to ensure you never get cracking, though Stonemonkey is bang on to say that that's not perfect - it's very good though. There's no need to perspective correct your r,g,b imho, there's enough error in the fact your using Gouraud and the RGB colour-space to make it irrelevant, just perspective correct the u,v, which is really important.
Jim
I'm of a slightly different opinion with regards to perspective correct rgb/shading, if it's on a textured surface then it's not really noticable but if the surface is a single colour then it can be. As you already have 1/(1/z) to get u and v then it's only an extra mul for each extra component in the inner loop.
For the first time in a while I've been looking at some code, as usual this is some cubes. With perspective correct shading and more accurate normal calculation than just averaging. Even though it's not textured I think the visible banding in the shading is due to the bi linear filtering and the shading calcs being combined. The bend in the shading is still a little noticable at some extreme angles but not noo bad.
L/R mouse buttons turn, both together move forward.