function clip_front(dst, src, icnt)
  local ocnt= 0

  -- TODO: no loop, vector-operation
  for i=0,icnt-1 do
    local x,y,z= src:get(0,i, 3)
    if (z<frontclip) then
      src:set(7,i, 1)
    else
      src:set(7,i, 0)
    end
  end

  local i1= icnt-1
  local c1= src:get(7,i1)
  for i2=0,icnt-1 do
    local c2= src:get(7,i2)

    if ( c1==0 ) then
      dst:copy(src, true, i1*8,ocnt*8, 8, 0,0,1)  -- dst[ocnt] = src[i1]
      ocnt+=1
    end

    if ( c1 != c2 ) then
      dst:copy(src, true, i2*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2]
      dst:sub( src, true, i1*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2] - src[i1]

      -- clip edge
      local t = (frontclip - src:get(2,i1)) / dst:get(2,ocnt)  -- (frontclip - src[i1].z) / (src[i2].z - src[i1].z)
      dst:mul(t,   true, 0,   ocnt*8, 1, 0,1, 5)  -- dst.xyzuv *= t
      dst:add(src, true, i1*8,ocnt*8, 8, 0,0, 1)  -- dst += src[i1]

      ocnt+=1
    end
    i1,c1= i2,c2
  end
  return ocnt
end


function clip_right(dst, src, icnt)
  local ocnt= 0

  -- TODO: no loop, vector-operation
  for i=0,icnt-1 do
    local x,y,z= src:get(0,i, 3)
    if (x>z) then
      src:set(7,i, 1)
    else
      src:set(7,i, 0)
    end
  end


  local i1= icnt-1
  local c1= src:get(7,i1)
  for i2=0,icnt-1 do
    local c2= src:get(7,i2)

    if (c1==0) then
      dst:copy(src, true, i1*8,ocnt*8, 8, 0,0,1)  -- dst[ocnt] = src[i1]
      ocnt+=1
    end

    -- TODO: xor
    if ( c1!=c2 ) then
      dst:copy(src, true, i2*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2]
      dst:sub( src, true, i1*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2] - src[i1]

      -- t= (v1.z - v1.x) / (v2.x - v1.x) - (v2.z-v1.z)
      local t= (src:get(2,i1)-src:get(0,i1)) / (dst:get(0,ocnt) - dst:get(2,ocnt))

      -- clip edge
      dst:mul(t,   true, 0,   ocnt*8, 1, 0,1, 7)  -- dst.xyzuv *= t
      dst:add(src, true, i1*8,ocnt*8, 8, 0,0, 1)  -- dst += src[i1]

      ocnt+=1
    end
    i1,c1= i2,c2
  end
  return ocnt
end


function clip_left(dst, src, icnt)
  local ocnt= 0

  -- TODO: no loop, vector-operation
  for i=0,icnt-1 do
    local x,y,z= src:get(0,i, 3)
    if (x<-z) then
      src:set(7,i, 1)
    else
      src:set(7,i, 0)
    end
  end


  local i1= icnt-1
  local c1= src:get(7,i1)
  for i2=0,icnt-1 do
    local c2= src:get(7,i2)

    if (c1==0) then
      dst:copy(src, true, i1*8,ocnt*8, 8, 0,0,1)  -- dst[ocnt] = src[i1]
      ocnt+=1
    end

    -- TODO: xor
    if ( c1!=c2 ) then
      dst:copy(src, true, i2*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2]
      dst:sub( src, true, i1*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2] - src[i1]

      -- t= -(v1.x + v1.z) / ((v2.x - v1.x) + (v2.z-v1.z))
      local t= -(src:get(0,i1)+src:get(2,i1)) / (dst:get(0,ocnt) + dst:get(2,ocnt))

      -- clip edge
      dst:mul(t,   true, 0,   ocnt*8, 1, 0,1, 5)  -- dst.xyzuv *= t
      dst:add(src, true, i1*8,ocnt*8, 8, 0,0, 1)  -- dst += src[i1]

      ocnt+=1
    end
    i1,c1= i2,c2
  end
  return ocnt
end


function clip_top(dst, src, icnt)
  local ocnt= 0

  -- TODO: no loop, vector-operation
  for i=0,icnt-1 do
    local x,y,z= src:get(0,i, 3)
    if (y<-z) then
      src:set(7,i, 1)
    else
      src:set(7,i, 0)
    end
  end


  local i1= icnt-1
  local c1= src:get(7,i1)
  for i2=0,icnt-1 do
    local c2= src:get(7,i2)

    if (c1==0) then
      dst:copy(src, true, i1*8,ocnt*8, 8, 0,0,1)  -- dst[ocnt] = src[i1]
      ocnt+=1
    end

    if ( c1!=c2 ) then
      dst:copy(src, true, i2*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2]
      dst:sub( src, true, i1*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2] - src[i1]

      -- t= (v1.z - v1.x) / (v2.x - v1.x) - (v2.z-v1.z)
      local t= -(src:get(1,i1)+src:get(2,i1)) / (dst:get(1,ocnt) + dst:get(2,ocnt))

      -- clip edge
      dst:mul(t,   true, 0,   ocnt*8, 1, 0,1, 5)  -- dst.xyzuv *= t
      dst:add(src, true, i1*8,ocnt*8, 8, 0,0, 1)  -- dst += src[i1]

      ocnt+=1
    end
    i1,c1= i2,c2
  end
  return ocnt
end


function clip_bottom(dst, src, icnt)
  local ocnt= 0

  -- TODO: no loop, vector-operation
  for i=0,icnt-1 do
    local x,y,z= src:get(0,i, 3)
    if (y>z) then
      src:set(7,i, 1)
    else
      src:set(7,i, 0)
    end
  end


  local i1= icnt-1
  local c1= src:get(7,i1)
  for i2=0,icnt-1 do
    local c2= src:get(7,i2)

    if (c1==0) then
      dst:copy(src, true, i1*8,ocnt*8, 8, 0,0,1)  -- dst[ocnt] = src[i1]
      ocnt+=1
    end

    if ( c1!=c2 ) then
      dst:copy(src, true, i2*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2]
      dst:sub( src, true, i1*8,ocnt*8, 8, 0,0,1) -- dst[ocnt] = src[i2] - src[i1]

      -- t= (v1.z - v1.y) / ((v2.y - v1.y) - (v2.z-v1.z))
      local t= (src:get(2,i1)-src:get(1,i1)) / (dst:get(1,ocnt) - dst:get(2,ocnt))

      -- clip edge
      dst:mul(t,   true, 0,   ocnt*8, 1, 0,1, 5)  -- dst.xyzuv *= t
      dst:add(src, true, i1*8,ocnt*8, 8, 0,0, 1)  -- dst += src[i1]

      ocnt+=1
    end
    i1,c1= i2,c2
  end
  return ocnt
end

