diff --git a/renderer3/hrend/image.go b/renderer3/hrend/image.go index 33617ca..2a63508 100644 --- a/renderer3/hrend/image.go +++ b/renderer3/hrend/image.go @@ -81,9 +81,11 @@ func (fb *SimpleFramebuffer) Get(x uint, y uint) (byte, byte, byte) { func (fb *SimpleFramebuffer) GetUv(u float32, v float32) (byte, byte, byte) { x := uint(float32(fb.Width)*u) & (fb.Width - 1) y := uint(float32(fb.Height)*(1-v)) & (fb.Height - 1) - return fb.Data[(x+y*fb.Width)*3], - fb.Data[(x+y*fb.Width)*3+1], - fb.Data[(x+y*fb.Width)*3+2] + i := (x + y*fb.Width) * 3 + return fb.Data[i], fb.Data[i+1], fb.Data[i+2] + // return fb.Data[(x+y*fb.Width)*3], + // fb.Data[(x+y*fb.Width)*3+1], + // fb.Data[(x+y*fb.Width)*3+2] } func NewSimpleFramebuffer(width uint, height uint) *SimpleFramebuffer { diff --git a/renderer3/hrend/math.go b/renderer3/hrend/math.go index 1a796de..d6ad3f0 100644 --- a/renderer3/hrend/math.go +++ b/renderer3/hrend/math.go @@ -321,6 +321,14 @@ func (v0 *Vec3f) Sub(v1 *Vec3f) *Vec3f { } } +func (v0 *Vec3f) Scale(s float32) *Vec3f { + return &Vec3f{ + X: v0.X * s, + Y: v0.Y * s, + Z: v0.Z * s, + } +} + func (v0 *Vec3f) CrossProduct(v1 *Vec3f) *Vec3f { return &Vec3f{ X: v0.Y*v1.Z - v0.Z*v1.Y, diff --git a/renderer3/hrend/obj.go b/renderer3/hrend/obj.go index 06220f2..f080384 100644 --- a/renderer3/hrend/obj.go +++ b/renderer3/hrend/obj.go @@ -18,17 +18,17 @@ type Vertex struct { type Facef [3]Vertex -// struct { -// Vertices [3]Vec3f -// TextureCoords [3]Vec2i -// } - type ObjModel struct { Vertices []Vec3f VTexture []Vec3f Faces []Facef } +func (o *ObjModel) ClearCachedVertexInfo() { + o.Vertices = nil + o.VTexture = nil +} + // Parse an obj file at the given reader. Only handles v and f right now func ParseObj(reader io.Reader) (*ObjModel, error) { result := ObjModel{ diff --git a/renderer3/hrend/render.go b/renderer3/hrend/render.go index dc86100..c8996f1 100644 --- a/renderer3/hrend/render.go +++ b/renderer3/hrend/render.go @@ -10,6 +10,7 @@ type ObjectDef struct { Texture Framebuffer // This needs to go somewhere else eventually! Pos Vec3f LookVec Vec3f + Color Vec3f Scale float32 Lighting bool } @@ -67,18 +68,19 @@ func ZClip(v0f Vec3f, v1f Vec3f, v2f Vec3f) bool { return maxz < -1 || maxz > 1 } -func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) { - if ZClip(v0f, v1f, v2f) { - return - } +func TriangleFlat(fb *RenderBuffer, color *Vec3f, v0f Vec3f, v1f Vec3f, v2f Vec3f) { v0 := v0f.ToVec2i() v1 := v1f.ToVec2i() v2 := v2f.ToVec2i() - r, g, b := Uint2Col(color) + //r, g, b := Uint2Col(color) boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2) if boundsBR.X < 0 || boundsBR.Y < 0 || boundsTL.X >= int(fb.Width) || boundsTL.Y >= int(fb.Height) { return } + parea := EdgeFunctioni(v0, v1, v2) + if parea <= 0 { + return + } if boundsTL.Y < 0 { boundsTL.Y = 0 } @@ -93,7 +95,6 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) } // Where to start our scanning pstart := Vec2i{boundsTL.X, boundsTL.Y} - parea := EdgeFunctioni(v0, v1, v2) invarea := 1 / float32(parea) w0_y := EdgeFunctioni(v1, v2, pstart) w1_y := EdgeFunctioni(v2, v0, pstart) @@ -101,6 +102,9 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) w0_xi, w0_yi := EdgeIncrementi(v1, v2) w1_xi, w1_yi := EdgeIncrementi(v2, v0) w2_xi, w2_yi := EdgeIncrementi(v0, v1) + r := byte(255 * color.X) + g := byte(255 * color.Y) + b := byte(255 * color.Z) for y := uint(boundsTL.Y); y <= uint(boundsBR.Y); y++ { w0 := w0_y @@ -139,12 +143,8 @@ func TriangleTextured(fb *RenderBuffer, texture Framebuffer, intensity float32, v1 := v1v.Pos.ToVec2i() v2 := v2v.Pos.ToVec2i() parea := EdgeFunctioni(v0, v1, v2) - // Still draw back faces (assume someone else culls them) - // if parea < 0 { - // log.Print("HEY", parea) - // v1, v2 = v2, v1 - // parea = EdgeFunctioni(v0, v1, v2) - // } + // Don't even bother with drawing backfaces or degenerate triangles; + // don't even give the user the option if parea <= 0 { return } @@ -245,4 +245,6 @@ func PerspectiveAndClip(face Facef, matrix3d *Mat44f) []Facef { // TODO: Now that we're here doing it like this, might as well remove faces // that are fully outside the other clipping zones. No need to do actual clipping... // just full rejections. This saves a BIT of processing... though not much + // NOTE: Uh no... this is too much effort. Two points could be outside individual + // planes and thus still intersect the screen. } diff --git a/renderer3/main.go b/renderer3/main.go index 5f5998c..8ec2c6f 100644 --- a/renderer3/main.go +++ b/renderer3/main.go @@ -43,6 +43,9 @@ func loadObject(name string) (*hrend.ObjModel, hrend.Framebuffer) { o, err := hrend.ParseObj(of) must(err) + // We also get rid of cached vertex info from the file + o.ClearCachedVertexInfo() + jf, err := os.Open(tfile) must(err) defer jf.Close() @@ -185,13 +188,19 @@ func main() { // And the actual objects for the scene. We also put the world in there objects := make([]*hrend.ObjectDef, 0) objects = append(objects, hrend.NewObjectDef(world, wtex)) + worldobj := objects[len(objects)-1] + worldobj.Color = hrend.Vec3f{0.0, 1.0, 0.0} objects = append(objects, hrend.NewObjectDef(sky, skytex)) // the actual skybox skyobj := objects[len(objects)-1] skyobj.Scale = 50 skyobj.Lighting = false + skyobj.Color = hrend.Vec3f{0.5, 0.5, 1.0} objects = append(objects, hrend.NewObjectDef(models[1], textures[1])) - objects[len(objects)-1].Pos.Y += 1 - objects[len(objects)-1].Pos.Z -= 2 + diabloobj := objects[len(objects)-1] + diabloobj.Pos.Y += 1 + diabloobj.Pos.Z -= 2 + diabloobj.Color = hrend.Vec3f{1.0, 0.0, 0.0} + //diabloobj.Lighting = false // These don't really change var projection hrend.Mat44f @@ -254,6 +263,7 @@ func main() { intensity = 1.0 } hrend.TriangleTextured(&rb, o.Texture, intensity, sc[0], sc[1], sc[2]) + //hrend.TriangleFlat(&rb, o.Color.Scale(intensity), sc[0].Pos, sc[1].Pos, sc[2].Pos) } //break // only render one face //hrend.TriangleFlat(&rb, hrend.Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0].Pos, sc[1].Pos, sc[2].Pos) diff --git a/renderer3/raybuffer.go b/renderer3/raybuffer.go index 6a6cc32..90c16e4 100644 --- a/renderer3/raybuffer.go +++ b/renderer3/raybuffer.go @@ -38,12 +38,16 @@ func (fb *RaylibBuffer) Dims() (uint, uint) { // Sure hope this gets inlined... func (fb *RaylibBuffer) Set(x uint, y uint, r byte, g byte, b byte) { - if x >= fb.Width || y >= fb.Height { - return - } - fb.Data[x+y*fb.Width].R = r - fb.Data[x+y*fb.Width].G = g - fb.Data[x+y*fb.Width].B = b + // if x >= fb.Width || y >= fb.Height { + // return + // } + // fb.Data[x+y*fb.Width].R = r + // fb.Data[x+y*fb.Width].G = g + // fb.Data[x+y*fb.Width].B = b + c := &fb.Data[x+y*fb.Width] + c.R = r + c.G = g + c.B = b } func (fb *RaylibBuffer) Get(x uint, y uint) (byte, byte, byte) { @@ -58,7 +62,9 @@ func (fb *RaylibBuffer) Get(x uint, y uint) (byte, byte, byte) { func (fb *RaylibBuffer) GetUv(u float32, v float32) (byte, byte, byte) { x := uint(float32(fb.Width)*u) & (fb.Width - 1) y := uint(float32(fb.Height)*(1-v)) & (fb.Height - 1) - return fb.Data[x+y*fb.Width].R, - fb.Data[x+y*fb.Width].G, - fb.Data[x+y*fb.Width].B + c := &fb.Data[x+y*fb.Width] + return c.R, c.G, c.B + // fb.Data[x+y*fb.Width].R, + // fb.Data[x+y*fb.Width].G, + // fb.Data[x+y*fb.Width].B }