// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vp8

// This file implements the prediction functions, as specified in chapter 12.
//
// For each macroblock (of 1x16x16 luma and 2x8x8 chroma coefficients), the
// luma values are either predicted as one large 16x16 region or 16 separate
// 4x4 regions. The chroma values are always predicted as one 8x8 region.
//
// For 4x4 regions, the target block's predicted values (Xs) are a function of
// its previously-decoded top and left border values, as well as a number of
// pixels from the top-right:
//
//	a b c d e f g h
//	p X X X X
//	q X X X X
//	r X X X X
//	s X X X X
//
// The predictor modes are:
//	- DC: all Xs = (b + c + d + e + p + q + r + s + 4) / 8.
//	- TM: the first X = (b + p - a), the second X = (c + p - a), and so on.
//	- VE: each X = the weighted average of its column's top value and that
//	      value's neighbors, i.e. averages of abc, bcd, cde or def.
//	- HE: similar to VE except rows instead of columns, and the final row is
//	      an average of r, s and s.
//	- RD, VR, LD, VL, HD, HU: these diagonal modes ("Right Down", "Vertical
//	      Right", etc) are more complicated and are described in section 12.3.
// All Xs are clipped to the range [0, 255].
//
// For 8x8 and 16x16 regions, the target block's predicted values are a
// function of the top and left border values without the top-right overhang,
// i.e. without the 8x8 or 16x16 equivalent of f, g and h. Furthermore:
//	- There are no diagonal predictor modes, only DC, TM, VE and HE.
//	- The DC mode has variants for macroblocks in the top row and/or left
//	  column, i.e. for macroblocks with mby == 0 || mbx == 0.
//	- The VE and HE modes take only the column top or row left values; they do
//	  not smooth that top/left value with its neighbors.

// nPred is the number of predictor modes, not including the Top/Left versions
// of the DC predictor mode.
const nPred = 10

const (
	predDC = iota
	predTM
	predVE
	predHE
	predRD
	predVR
	predLD
	predVL
	predHD
	predHU
	predDCTop
	predDCLeft
	predDCTopLeft
)

func checkTopLeftPred(,  int,  uint8) uint8 {
	if  != predDC {
		return 
	}
	if  == 0 {
		if  == 0 {
			return predDCTopLeft
		}
		return predDCLeft
	}
	if  == 0 {
		return predDCTop
	}
	return predDC
}

var predFunc4 = [...]func(*Decoder, int, int){
	predFunc4DC,
	predFunc4TM,
	predFunc4VE,
	predFunc4HE,
	predFunc4RD,
	predFunc4VR,
	predFunc4LD,
	predFunc4VL,
	predFunc4HD,
	predFunc4HU,
	nil,
	nil,
	nil,
}

var predFunc8 = [...]func(*Decoder, int, int){
	predFunc8DC,
	predFunc8TM,
	predFunc8VE,
	predFunc8HE,
	nil,
	nil,
	nil,
	nil,
	nil,
	nil,
	predFunc8DCTop,
	predFunc8DCLeft,
	predFunc8DCTopLeft,
}

var predFunc16 = [...]func(*Decoder, int, int){
	predFunc16DC,
	predFunc16TM,
	predFunc16VE,
	predFunc16HE,
	nil,
	nil,
	nil,
	nil,
	nil,
	nil,
	predFunc16DCTop,
	predFunc16DCLeft,
	predFunc16DCTopLeft,
}

func predFunc4DC( *Decoder, ,  int) {
	 := uint32(4)
	for  := 0;  < 4; ++ {
		 += uint32(.ybr[-1][+])
	}
	for  := 0;  < 4; ++ {
		 += uint32(.ybr[+][-1])
	}
	 := uint8( / 8)
	for  := 0;  < 4; ++ {
		for  := 0;  < 4; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc4TM( *Decoder, ,  int) {
	 := -int32(.ybr[-1][-1])
	for  := 0;  < 4; ++ {
		 :=  + int32(.ybr[+][-1])
		for  := 0;  < 4; ++ {
			 :=  + int32(.ybr[-1][+])
			.ybr[+][+] = uint8(clip(, 0, 255))
		}
	}
}

func predFunc4VE( *Decoder, ,  int) {
	 := int32(.ybr[-1][-1])
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := int32(.ybr[-1][+3])
	 := int32(.ybr[-1][+4])
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	for  := 0;  < 4; ++ {
		.ybr[+][+0] = 
		.ybr[+][+1] = 
		.ybr[+][+2] = 
		.ybr[+][+3] = 
	}
}

func predFunc4HE( *Decoder, ,  int) {
	 := int32(.ybr[+3][-1])
	 := int32(.ybr[+2][-1])
	 := int32(.ybr[+1][-1])
	 := int32(.ybr[+0][-1])
	 := int32(.ybr[-1][-1])
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	for  := 0;  < 4; ++ {
		.ybr[+0][+] = 
		.ybr[+1][+] = 
		.ybr[+2][+] = 
		.ybr[+3][+] = 
	}
}

func predFunc4RD( *Decoder, ,  int) {
	 := int32(.ybr[+3][-1])
	 := int32(.ybr[+2][-1])
	 := int32(.ybr[+1][-1])
	 := int32(.ybr[+0][-1])
	 := int32(.ybr[-1][-1])
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := int32(.ybr[-1][+3])
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc4VR( *Decoder, ,  int) {
	 := int32(.ybr[+2][-1])
	 := int32(.ybr[+1][-1])
	 := int32(.ybr[+0][-1])
	 := int32(.ybr[-1][-1])
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := int32(.ybr[-1][+3])
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc4LD( *Decoder, ,  int) {
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := int32(.ybr[-1][+3])
	 := int32(.ybr[-1][+4])
	 := int32(.ybr[-1][+5])
	 := int32(.ybr[-1][+6])
	 := int32(.ybr[-1][+7])
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc4VL( *Decoder, ,  int) {
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := int32(.ybr[-1][+3])
	 := int32(.ybr[-1][+4])
	 := int32(.ybr[-1][+5])
	 := int32(.ybr[-1][+6])
	 := int32(.ybr[-1][+7])
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc4HD( *Decoder, ,  int) {
	 := int32(.ybr[+3][-1])
	 := int32(.ybr[+2][-1])
	 := int32(.ybr[+1][-1])
	 := int32(.ybr[+0][-1])
	 := int32(.ybr[-1][-1])
	 := int32(.ybr[-1][+0])
	 := int32(.ybr[-1][+1])
	 := int32(.ybr[-1][+2])
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc4HU( *Decoder, ,  int) {
	 := int32(.ybr[+3][-1])
	 := int32(.ybr[+2][-1])
	 := int32(.ybr[+1][-1])
	 := int32(.ybr[+0][-1])
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( +  + 1) / 2)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8(( + 2* +  + 2) / 4)
	 := uint8()
	.ybr[+0][+0] = 
	.ybr[+0][+1] = 
	.ybr[+0][+2] = 
	.ybr[+0][+3] = 
	.ybr[+1][+0] = 
	.ybr[+1][+1] = 
	.ybr[+1][+2] = 
	.ybr[+1][+3] = 
	.ybr[+2][+0] = 
	.ybr[+2][+1] = 
	.ybr[+2][+2] = 
	.ybr[+2][+3] = 
	.ybr[+3][+0] = 
	.ybr[+3][+1] = 
	.ybr[+3][+2] = 
	.ybr[+3][+3] = 
}

func predFunc8DC( *Decoder, ,  int) {
	 := uint32(8)
	for  := 0;  < 8; ++ {
		 += uint32(.ybr[-1][+])
	}
	for  := 0;  < 8; ++ {
		 += uint32(.ybr[+][-1])
	}
	 := uint8( / 16)
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc8TM( *Decoder, ,  int) {
	 := -int32(.ybr[-1][-1])
	for  := 0;  < 8; ++ {
		 :=  + int32(.ybr[+][-1])
		for  := 0;  < 8; ++ {
			 :=  + int32(.ybr[-1][+])
			.ybr[+][+] = uint8(clip(, 0, 255))
		}
	}
}

func predFunc8VE( *Decoder, ,  int) {
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = .ybr[-1][+]
		}
	}
}

func predFunc8HE( *Decoder, ,  int) {
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = .ybr[+][-1]
		}
	}
}

func predFunc8DCTop( *Decoder, ,  int) {
	 := uint32(4)
	for  := 0;  < 8; ++ {
		 += uint32(.ybr[+][-1])
	}
	 := uint8( / 8)
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc8DCLeft( *Decoder, ,  int) {
	 := uint32(4)
	for  := 0;  < 8; ++ {
		 += uint32(.ybr[-1][+])
	}
	 := uint8( / 8)
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc8DCTopLeft( *Decoder, ,  int) {
	for  := 0;  < 8; ++ {
		for  := 0;  < 8; ++ {
			.ybr[+][+] = 0x80
		}
	}
}

func predFunc16DC( *Decoder, ,  int) {
	 := uint32(16)
	for  := 0;  < 16; ++ {
		 += uint32(.ybr[-1][+])
	}
	for  := 0;  < 16; ++ {
		 += uint32(.ybr[+][-1])
	}
	 := uint8( / 32)
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc16TM( *Decoder, ,  int) {
	 := -int32(.ybr[-1][-1])
	for  := 0;  < 16; ++ {
		 :=  + int32(.ybr[+][-1])
		for  := 0;  < 16; ++ {
			 :=  + int32(.ybr[-1][+])
			.ybr[+][+] = uint8(clip(, 0, 255))
		}
	}
}

func predFunc16VE( *Decoder, ,  int) {
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = .ybr[-1][+]
		}
	}
}

func predFunc16HE( *Decoder, ,  int) {
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = .ybr[+][-1]
		}
	}
}

func predFunc16DCTop( *Decoder, ,  int) {
	 := uint32(8)
	for  := 0;  < 16; ++ {
		 += uint32(.ybr[+][-1])
	}
	 := uint8( / 16)
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc16DCLeft( *Decoder, ,  int) {
	 := uint32(8)
	for  := 0;  < 16; ++ {
		 += uint32(.ybr[-1][+])
	}
	 := uint8( / 16)
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = 
		}
	}
}

func predFunc16DCTopLeft( *Decoder, ,  int) {
	for  := 0;  < 16; ++ {
		for  := 0;  < 16; ++ {
			.ybr[+][+] = 0x80
		}
	}
}