i need an intersection for every pixel row multiply every wall
and believe me: this doesnt taka a nanosec! drawing a single pixel (not including flipping it) takes 7 nanosecs!!! doing a single multiplication takes 6 nanosecounds.
what i just tried is a way like a software renderer. you can only do quads which have a certain height and two x|z coordinates. those quads are projected, clipped and textured just like polygons, only optimized for quads. i will post a demo here soon, but this is slow anyway :(
Graphics SCREEN_W, SCREEN_H, 32, 2
SetBuffer BackBuffer()
;Globs
Const SCREEN_W = 400, SCREEN_H = 300
Const CLIP_NEAR# = 3, CLIP_FAR# = 10
Type Segment
Field p1x#, p1z#, p2x#, p2z#
Field y#, h#
Field tex.Texture
Field p1u#, p1v#, p2u#, p2v#
End Type
Type Texture
Field w, h, texel[64 * 64 * 4]
End Type
Global FPS, FPSFrame, FPSTime
Dim ZBuffer#(SCREEN_W, SCREEN_H)
Global CamX#, CamZ# = -8, CamYaw#
Global WalkXS#, WalkZS#, WalkRotS#
tex = LoadTex("Texture.png")
CreateCube(0, 0, 3, 1, 1, 1, tex)
MoveMouse SCREEN_W / 2, SCREEN_H / 2
FlushMouse()
FlushKeys()
While Not KeyHit(1)
Cls
Controls()
Raycast(CamX#, CamZ#, CamYaw#)
Text 10, 10, "FPS: " + GetFPS()
Flip ;0
Wend
End
Function Controls()
s# = .1
WalkZS# = (WalkZS# + (KeyDown(17) - KeyDown(31)) * s#) * .8
WalkXS# = (WalkXS# + (KeyDown(30) - KeyDown(32)) * s#) * .8
Slide(CamYaw#, WalkZS#)
Slide(CamYaw# - 90, WalkXS#)
WalkRotS# = (WalkRotS# + MouseXSpeed()) * .5
CamYaw# = CamYaw# + WalkRotS#
MoveMouse SCREEN_W / 2, SCREEN_H / 2
End Function
Function Slide(yaw#, speed#)
CamX# = CamX# + Sin(yaw#) * speed#
CamZ# = CamZ# + Cos(yaw#) * speed#
End Function
Function CreateCube(x#, y#, z#, sx#, sy#, sz#, tex)
CreateSegment(x# - sx#, z# + sz#, x# - sx#, z# - sz#, y#, sy#, tex)
CreateSegment(x# - sx#, z# + sz#, x# + sx#, z# + sz#, y#, sy#, tex)
CreateSegment(x# + sx#, z# + sz#, x# + sx#, z# - sz#, y#, sy#, tex)
CreateSegment(x# + sx#, z# - sz#, x# - sx#, z# - sz#, y#, sy#, tex)
End Function
Function CreateSegment(p1x#, p1z#, p2x#, p2z#, y#, h#, tex)
seg.Segment = New Segment
seg\p1x# = p1x#
seg\p1z# = p1z#
seg\p2x# = p2x#
seg\p2z# = p2z#
seg\y# = y#
seg\h# = h#
seg\p1u# = 0
seg\p1v# = 0
seg\tex = Object.Texture(tex)
seg\p2u# = seg\tex\w
seg\p2v# = seg\tex\h
End Function
Function Raycast(cam_x#, cam_z#, cam_yaw#)
For x = 0 To SCREEN_W - 1
For y = 0 To SCREEN_H - 1
ZBuffer(x, y) = CLIP_FAR#
Next
Next
LockBuffer()
sine# = Sin(-cam_yaw#)
cosi# = Cos(-cam_yaw#)
For seg.Segment = Each Segment
p1x# = -(cam_x# + seg\p1x#) * cosi# - (cam_z# + seg\p1z#) * sine#
p1z# = (cam_x# + seg\p1x#) * sine# - (cam_z# + seg\p1z#) * cosi#
p2x# = -(cam_x# + seg\p2x#) * cosi# - (cam_z# + seg\p2z#) * sine#
p2z# = (cam_x# + seg\p2x#) * sine# - (cam_z# + seg\p2z#) * cosi#
If p1z# > CLIP_NEAR# And p2z# > CLIP_NEAR# Then
SegmentLine(p1x#, p1z#, p2x#, p2z#, seg\y#, seg\h#, seg\tex, seg\p1u#, seg\p1v#, seg\p2u#, seg\p2v#)
AppTitle 0
ElseIf p1z# < CLIP_NEAR# Xor p2z# < CLIP_NEAR# Then
AppTitle 1
p12x# = Intpf(CLIP_NEAR#, p1z#, p2z#, p1x#, p2x#)
p12u# = Intpf(CLIP_NEAR#, p1z#, p2z#, p1u#, p2u#)
If p1z# < CLIP_NEAR# Then
AppTitle "1.1"
SegmentLine(p12x#, CLIP_NEAR#, p2x#, p2z#, seg\y#, seg\h#, seg\tex, p12u#, seg\p1v#, seg\p2u#, seg\p2v#)
ElseIf p2z# < CLIP_NEAR# Then
AppTitle "1.2"
SegmentLine(p1x#, p1z#, p12x#, CLIP_NEAR#, seg\y#, seg\h#, seg\tex, seg\p1u#, seg\p1v#, p12u#, seg\p2v#)
EndIf
Else
AppTitle 3
EndIf
Next
UnlockBuffer()
End Function
Function SegmentLine(p1x#, p1z#, p2x#, p2z#, y#, h#, tex.Texture, p1u#, p1v#, p2u#, p2v#)
gw2 = SCREEN_W / 2
gh2 = SCREEN_H / 2
x1 = p1x# * SCREEN_W / p1z# + gw2
x2 = p2x# * SCREEN_W / p2z# + gw2
y1 = (y# - 1) * h# * SCREEN_W / p1z# + gh2
y2 = (y# - 1) * h# * SCREEN_W / p2z# + gh2
y3 = (y# + 1) * h# * SCREEN_W / p1z# + gh2
y4 = (y# + 1) * h# * SCREEN_W / p2z# + gh2
DrawSegmentLine(x1, x2, y1, y2, y3, y4, tex, p1u#, p1v#, p2u#, p2v#, p1z#, p2z#)
End Function
Function DrawSegmentLine(x1, x2, y1, y2, y3, y4, tex.Texture, u1#, v1#, u2#, v2#, d1#, d2#)
If x1 > x2 Then
xt = x1
x1 = x2
x2 = xt
yt = y1
y1 = y2
y2 = yt
yt = y3
y3 = y4
y4 = yt
ut# = u1#
u1# = u2#
u2# = ut#
dt# = d1#
d1# = d2#
d2# = dt#
EndIf
d1# = 1 / d1#
d2# = 1 / d2#
u1# = (u1# - .5) * d1#
v1# = (v1# - .5)
u2# = (u2# - .5) * d2#
v2# = (v2# - .5)
For x = x1 To x2
If x => SCREEN_W Then Exit
If x > -1 Then
p1y = Intpf(x, x1, x2, y1, y2)
p2y = Intpf(x, x1, x2, y3, y4)
u# = Intpf(x, x1, x2, u1#, u2#)
d# = Intpf(x, x1, x2, d1#, d2#)
For y = p1y To p2y
If y => SCREEN_H Then Exit
If y > -1 Then
If ZBuffer(x, y) > -d# Then
v = Intpf(y, p1y, p2y, v1#, v2#)
WritePixelFast x, y, tex\texel[(v * tex\w + Int(u# / d#)) * 4]
ZBuffer(x, y) = -d#
EndIf
EndIf
Next
EndIf
Next
End Function
Function LoadTex(path$)
tex.Texture = New Texture
img = LoadImage(path$)
tex\w = ImageWidth(img)
tex\h = ImageHeight(img)
LockBuffer ImageBuffer(img)
For x = 0 To tex\w - 1
For y = 0 To tex\h - 1
tex\texel[(y * tex\w + x) * 4] = ReadPixelFast(x, y, ImageBuffer(img))
Next
Next
UnlockBuffer ImageBuffer(img)
Return Handle(tex)
End Function
Function GetFPS(ms# = 1000)
ctime = MilliSecs()
FPSFrame = FPSFrame + 1
If ctime - FPSTime > ms# Then
FPS = FPSFrame * 1000 / ms#
FPSFrame = 0
FPSTime = ctime
EndIf
Return FPS
End Function
Function Intpf#(value#, vMin#, vMax#, retMin#, retMax#)
Return retMin# + (value# - vMin#) * (retMax# - retMin#) / (vMax# - vMin#)
End Function
Function Intp(value, vMin, vMax, retMin, retMax)
Return retMin + (value - vMin) * (retMax - retMin) / (vMax - vMin)
End Function