func drawFloor(room *Room, floor mathgl.Mat4, temp *WallTexture, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64, floor_drawer []FloorDrawer) { gl.MatrixMode(gl.MODELVIEW) gl.PushMatrix() gl.LoadIdentity() gl.MultMatrixf(&floor[0]) defer gl.PopMatrix() gl.Enable(gl.STENCIL_TEST) defer gl.Disable(gl.STENCIL_TEST) gl.StencilFunc(gl.ALWAYS, 4, 4) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) gl.Disable(gl.TEXTURE_2D) gl.Begin(gl.QUADS) gl.Vertex2i(0, 0) gl.Vertex2i(0, room.Size.Dy) gl.Vertex2i(room.Size.Dx, room.Size.Dy) gl.Vertex2i(room.Size.Dx, 0) gl.End() gl.StencilFunc(gl.EQUAL, 4, 15) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) // Draw the floor gl.Enable(gl.TEXTURE_2D) cstack.ApplyWithAlpha(los_alpha) room.Floor.Data().Render(0, 0, float64(room.Size.Dx), float64(room.Size.Dy)) if los_tex != nil { los_tex.Bind() gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA) gl.Color4d(0, 0, 0, 1) gl.Begin(gl.QUADS) gl.TexCoord2i(0, 0) gl.Vertex2i(-room.X, -room.Y) gl.TexCoord2i(1, 0) gl.Vertex2i(-room.X, los_tex.Size()-room.Y) gl.TexCoord2i(1, 1) gl.Vertex2i(los_tex.Size()-room.X, los_tex.Size()-room.Y) gl.TexCoord2i(0, 1) gl.Vertex2i(los_tex.Size()-room.X, -room.Y) gl.End() gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } cstack.ApplyWithAlpha(los_alpha) { g_texs = g_texs[0:0] if temp != nil { g_texs = append(g_texs, *temp) } for _, tex := range room.WallTextures { g_texs = append(g_texs, *tex) } for i, tex := range g_texs { if tex.X >= float32(room.Size.Dx) { tex.Rot -= 3.1415926535 / 2 } if temp != nil && i == 0 { cstack.Push(1, 0.7, 0.7, 0.7) } cstack.ApplyWithAlpha(los_alpha) tex.Render() if temp != nil && i == 0 { cstack.Pop() } } } gl.PushMatrix() gl.Translated(-float64(room.X), -float64(room.Y), 0) for _, fd := range floor_drawer { fd.RenderOnFloor() } gl.PopMatrix() // Re-enable textures because floor_drawer.RenderOnFloor() might have // disabled them gl.Enable(gl.TEXTURE_2D) gl.StencilFunc(gl.ALWAYS, 5, 5) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) gl.Disable(gl.TEXTURE_2D) gl.Color4d(0, 0, 0, 0) gl.Begin(gl.QUADS) gl.Vertex2i(0, 0) gl.Vertex2i(0, room.Size.Dy) gl.Vertex2i(room.Size.Dx, room.Size.Dy) gl.Vertex2i(room.Size.Dx, 0) gl.End() }
func drawFurniture(roomx, roomy int, mat mathgl.Mat4, zoom float32, furniture []*Furniture, temp_furniture *Furniture, extras []Drawable, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64) { gl.Enable(gl.TEXTURE_2D) gl.Color4d(1, 1, 1, los_alpha) gl.PushMatrix() gl.LoadIdentity() board_to_window := func(mx, my float32) (x, y float32) { v := mathgl.Vec4{X: mx, Y: my, W: 1} v.Transform(&mat) x, y = v.X, v.Y return } g_stuff = g_stuff[0:0] for i := range furniture { g_stuff = append(g_stuff, furniture[i]) } if temp_furniture != nil { g_stuff = append(g_stuff, temp_furniture) } for i := range extras { g_stuff = append(g_stuff, extras[i]) } g_stuff = OrderRectObjects(g_stuff) for i := len(g_stuff) - 1; i >= 0; i-- { f := g_stuff[i] var near_x, near_y, dx, dy float32 idx, idy := f.Dims() dx = float32(idx) dy = float32(idy) switch d := f.(type) { case *Furniture: ix, iy := d.Pos() near_x = float32(ix) near_y = float32(iy) case Drawable: fx, fy := d.FPos() near_x = float32(fx) near_y = float32(fy) } vis_tot := 1.0 if los_tex != nil { vis_tot = 0.0 // If we're looking at a piece of furniture that blocks Los then we // can't expect to have Los to all of it, so we will check the squares // around it. Full visibility will mean that half of the surrounding // cells are visible. blocks_los := false // Also need to check if it is an enemy unit if _, ok := f.(*Furniture); ok { blocks_los = true } if blocks_los { for x := near_x - 1; x < near_x+dx+1; x++ { vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(near_y-1)+roomy]) vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(near_y+dy+1)+roomy]) } for y := near_y; y < near_y+dy; y++ { vis_tot += float64(los_tex.Pix()[int(near_x-1)+roomx][int(y)+roomy]) vis_tot += float64(los_tex.Pix()[int(near_x+dx+1)+roomx][int(y)+roomy]) } vis_tot /= float64((dx*2 + dy*2 + 4) * 255 / 2) if vis_tot > 1 { vis_tot = 1 } } else { for x := near_x; x < near_x+dx; x++ { for y := near_y; y < near_y+dy; y++ { vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(y)+roomy]) } } vis_tot /= float64(dx * dy * 255) } } leftx, _ := board_to_window(near_x, near_y+dy) rightx, _ := board_to_window(near_x+dx, near_y) _, boty := board_to_window(near_x, near_y) if f == temp_furniture { cstack.Push(1, 0, 0, 0.4) } else { bot := (LosMinVisibility / 255.0) vis := (vis_tot - bot) / (1 - bot) vis = vis * vis vis = vis*(1-bot) + bot vis = vis * vis cstack.Push(vis, vis, vis, 1) } cstack.ApplyWithAlpha(los_alpha) cstack.Pop() switch d := f.(type) { case *Furniture: d.Render(mathgl.Vec2{leftx, boty}, rightx-leftx) case Drawable: gl.Enable(gl.TEXTURE_2D) x := (leftx + rightx) / 2 d.Render(mathgl.Vec2{x, boty}, rightx-leftx) } } gl.PopMatrix() }
// room: the wall to draw // wall: the texture to render on the wall // temp: an additional texture to render along with the other detail textures // specified in room // left,right: the xy planes of the left and right walls func drawWall(room *Room, floor, left, right mathgl.Mat4, temp_tex *WallTexture, temp_door doorInfo, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64) { gl.Enable(gl.STENCIL_TEST) defer gl.Disable(gl.STENCIL_TEST) gl.MatrixMode(gl.MODELVIEW) gl.PushMatrix() defer gl.PopMatrix() var dz int if room.Wall.Data().Dx() > 0 { dz = room.Wall.Data().Dy() * (room.Size.Dx + room.Size.Dy) / room.Wall.Data().Dx() } corner := float32(room.Size.Dx) / float32(room.Size.Dx+room.Size.Dy) gl.LoadIdentity() gl.MultMatrixf(&floor[0]) g_texs = g_texs[0:0] if temp_tex != nil { g_texs = append(g_texs, *temp_tex) } for _, tex := range room.WallTextures { g_texs = append(g_texs, *tex) } do_right_wall := func() { gl.Begin(gl.QUADS) gl.TexCoord2f(1, 0) gl.Vertex3i(room.Size.Dx, 0, 0) gl.TexCoord2f(1, -1) gl.Vertex3i(room.Size.Dx, 0, -dz) gl.TexCoord2f(corner, -1) gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz) gl.TexCoord2f(corner, 0) gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0) gl.End() } g_doors = g_doors[0:0] for _, door := range room.Doors { g_doors = append(g_doors, door) } if temp_door.Door != nil { g_doors = append(g_doors, temp_door.Door) } alpha := 0.2 do_right_doors := func(opened bool) { for _, door := range g_doors { if door.Facing != FarRight { continue } if door.IsOpened() != opened { continue } door.TextureData().Bind() if door == temp_door.Door { if temp_door.Valid { cstack.Push(0, 0, 1, alpha) } else { cstack.Push(1, 0, 0, alpha) } } cstack.ApplyWithAlpha(alpha * los_alpha) gl.Begin(gl.QUADS) height := float64(door.Width*door.TextureData().Dy()) / float64(door.TextureData().Dx()) gl.TexCoord2f(1, 0) gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos), 0) gl.TexCoord2f(1, -1) gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos), -height) gl.TexCoord2f(0, -1) gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos+door.Width), -height) gl.TexCoord2f(0, 0) gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos+door.Width), 0) gl.End() if door == temp_door.Door { cstack.Pop() } } } // Right wall gl.StencilFunc(gl.NOTEQUAL, 8, 7) gl.StencilOp(gl.DECR_WRAP, gl.REPLACE, gl.REPLACE) gl.Color4d(0, 0, 0, 0) do_right_wall() gl.Enable(gl.TEXTURE_2D) cstack.ApplyWithAlpha(alpha * los_alpha) gl.StencilFunc(gl.EQUAL, 8, 15) gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO) do_right_doors(true) cstack.ApplyWithAlpha(1.0 * los_alpha) gl.StencilFunc(gl.EQUAL, 15, 15) gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO) do_right_doors(true) for _, alpha := range []float64{alpha, 1.0} { cstack.ApplyWithAlpha(alpha * los_alpha) if alpha == 1.0 { gl.StencilFunc(gl.EQUAL, 15, 15) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) } else { gl.StencilFunc(gl.EQUAL, 8, 15) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) } room.Wall.Data().Bind() do_right_wall() gl.PushMatrix() gl.LoadIdentity() gl.MultMatrixf(&right[0]) for i, tex := range g_texs { dx, dy := float32(room.Size.Dx), float32(room.Size.Dy) if tex.Y > dy { tex.X, tex.Y = dx+tex.Y-dy, dy+dx-tex.X } if tex.X > dx { tex.Rot -= 3.1415926535 / 2 } tex.X -= dx if temp_tex != nil && i == 0 { cstack.Push(1, 0.7, 0.7, 0.7) } cstack.ApplyWithAlpha(alpha * los_alpha) tex.Render() if temp_tex != nil && i == 0 { cstack.Pop() } } gl.PopMatrix() } cstack.ApplyWithAlpha(alpha * los_alpha) gl.StencilFunc(gl.EQUAL, 8, 15) do_right_doors(false) cstack.ApplyWithAlpha(1.0 * los_alpha) gl.StencilFunc(gl.EQUAL, 15, 15) do_right_doors(false) // Go back over the area we just drew on and replace it with all b0001 gl.StencilFunc(gl.ALWAYS, 1, 1) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) gl.Color4d(0, 0, 0, 0) do_right_wall() // Now that the entire wall has been draw we can cast shadows on it if we've // got a los texture if los_tex != nil { los_tex.Bind() gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA) gl.Color4d(0, 0, 0, 1) tx := (float64(room.X+room.Size.Dx) - 0.5) / float64(los_tex.Size()) ty := (float64(room.Y) + 0.5) / float64(los_tex.Size()) ty2 := (float64(room.Y+room.Size.Dy) - 0.5) / float64(los_tex.Size()) gl.Begin(gl.QUADS) gl.TexCoord2d(ty, tx) gl.Vertex3i(room.Size.Dx, 0, 0) gl.TexCoord2d(ty, tx) gl.Vertex3i(room.Size.Dx, 0, -dz) gl.TexCoord2d(ty2, tx) gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz) gl.TexCoord2d(ty2, tx) gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0) gl.End() gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } do_left_wall := func() { gl.Begin(gl.QUADS) gl.TexCoord2f(corner, 0) gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0) gl.TexCoord2f(corner, -1) gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz) gl.TexCoord2f(0, -1) gl.Vertex3i(0, room.Size.Dy, -dz) gl.TexCoord2f(0, 0) gl.Vertex3i(0, room.Size.Dy, 0) gl.End() } do_left_doors := func(opened bool) { for _, door := range g_doors { if door.Facing != FarLeft { continue } if door.IsOpened() != opened { continue } door.TextureData().Bind() if door == temp_door.Door { if temp_door.Valid { cstack.Push(0, 0, 1, alpha) } else { cstack.Push(1, 0, 0, alpha) } } cstack.ApplyWithAlpha(alpha * los_alpha) gl.Begin(gl.QUADS) height := float64(door.Width*door.TextureData().Dy()) / float64(door.TextureData().Dx()) gl.TexCoord2f(0, 0) gl.Vertex3d(float64(door.Pos), float64(room.Size.Dy), 0) gl.TexCoord2f(0, -1) gl.Vertex3d(float64(door.Pos), float64(room.Size.Dy), -height) gl.TexCoord2f(1, -1) gl.Vertex3d(float64(door.Pos+door.Width), float64(room.Size.Dy), -height) gl.TexCoord2f(1, 0) gl.Vertex3d(float64(door.Pos+door.Width), float64(room.Size.Dy), 0) gl.End() if door == temp_door.Door { cstack.Pop() } } } gl.StencilFunc(gl.NOTEQUAL, 8, 7) gl.StencilOp(gl.DECR_WRAP, gl.REPLACE, gl.REPLACE) gl.Color4d(0, 0, 0, 0) do_left_wall() gl.Enable(gl.TEXTURE_2D) cstack.ApplyWithAlpha(alpha * los_alpha) gl.StencilFunc(gl.EQUAL, 8, 15) gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO) do_left_doors(true) cstack.ApplyWithAlpha(1.0 * los_alpha) gl.StencilFunc(gl.EQUAL, 15, 15) gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO) do_left_doors(true) for _, alpha := range []float64{alpha, 1.0} { if alpha == 1.0 { gl.StencilFunc(gl.EQUAL, 15, 15) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) } else { gl.StencilFunc(gl.EQUAL, 8, 15) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) } room.Wall.Data().Bind() cstack.ApplyWithAlpha(alpha * los_alpha) do_left_wall() gl.PushMatrix() gl.LoadIdentity() gl.MultMatrixf(&left[0]) for i, tex := range g_texs { dx, dy := float32(room.Size.Dx), float32(room.Size.Dy) if tex.X > dx { tex.X, tex.Y = dx+dy-tex.Y, dy+tex.X-dx } tex.Y -= dy if temp_tex != nil && i == 0 { cstack.Push(1, 0.7, 0.7, 0.7) } cstack.ApplyWithAlpha(alpha * los_alpha) tex.Render() if temp_tex != nil && i == 0 { cstack.Pop() } } gl.PopMatrix() } cstack.ApplyWithAlpha(alpha * los_alpha) gl.StencilFunc(gl.EQUAL, 8, 15) do_left_doors(false) cstack.ApplyWithAlpha(1.0 * los_alpha) gl.StencilFunc(gl.EQUAL, 15, 15) do_left_doors(false) // Go back over the area we just drew on and replace it with all b0010 gl.StencilFunc(gl.ALWAYS, 2, 2) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) gl.Color4d(0, 0, 0, 0) do_left_wall() // Now that the entire wall has been draw we can cast shadows on it if we've // got a los texture if los_tex != nil { los_tex.Bind() gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA) gl.Color4d(0, 0, 0, 1) ty := (float64(room.Y+room.Size.Dy) - 0.5) / float64(los_tex.Size()) tx := (float64(room.X) + 0.5) / float64(los_tex.Size()) tx2 := (float64(room.X+room.Size.Dx) - 0.5) / float64(los_tex.Size()) gl.Begin(gl.QUADS) gl.TexCoord2d(ty, tx) gl.Vertex3i(0, room.Size.Dy, 0) gl.TexCoord2d(ty, tx) gl.Vertex3i(0, room.Size.Dy, -dz) gl.TexCoord2d(ty, tx2) gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz) gl.TexCoord2d(ty, tx2) gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0) gl.End() gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } }