#!/usr/bin/env python
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2011, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Nathan Letwory.
#
# ***** END GPL LICENSE BLOCK *****

from os import path
Import('env')

cycles = env.Clone()

cycles.Depends('../../source/blender/makesrna/intern/RNA_blender_cpp.h', 'makesrna')

sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob('kernel/*.cpp') + cycles.Glob('render/*.cpp') + cycles.Glob('subd/*.cpp') + cycles.Glob('util/*.cpp') + cycles.Glob('blender/*.cpp')

sources.remove(path.join('util', 'util_view.cpp'))
sources.remove(path.join('kernel', 'kernel_sse2.cpp'))
sources.remove(path.join('kernel', 'kernel_sse3.cpp'))
sources.remove(path.join('kernel', 'kernel_sse41.cpp'))
sources.remove(path.join('kernel', 'kernel_avx.cpp'))
sources.remove(path.join('kernel', 'kernel_avx2.cpp'))

incs = [] 
defs = []
cxxflags = Split(env['CXXFLAGS'])

defs += env['BF_GL_DEFINITIONS']

defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
defs.append('CCL_NAMESPACE_END=}')

defs.append('WITH_OPENCL')
defs.append('WITH_MULTI')
defs.append('WITH_CUDA')

if env['WITH_BF_CYCLES_OSL']:
    defs.append('WITH_OSL')
    defs.append('OSL_STATIC_LIBRARY')
    incs.append(cycles['BF_OSL_INC'])

if env['WITH_BF_CYCLES_DEBUG']:
    defs.append('WITH_CYCLES_DEBUG')

if env['WITH_BF_CYCLES_LOGGING']:
    defs.append('WITH_CYCLES_LOGGING')
    defs.append('GOOGLE_GLOG_DLL_DECL=')
    defs.append('CYCLES_GFLAGS_NAMESPACE=gflags')
    if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
        incs.append('#extern/libmv/third_party/glog/src/windows')
        incs.append('#extern/libmv/third_party/gflags')
    else:
        incs.append('#extern/libmv/third_party/glog/src')
        incs.append('#extern/libmv/third_party/gflags')

incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna #source/blender/blenlib'.split())
incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())

incs.append(env['BF_GLEW_INC'])
incs.append('#/intern/glew-mx')
incs.append('#/intern/atomic')
incs.append('#intern/mikktspace')
incs.extend('#extern/glew/include #extern/clew/include #extern/cuew/include #intern/mikktspace'.split())

incs.append(cycles['BF_OIIO_INC'])
incs.append(cycles['BF_BOOST_INC'])
incs.append(cycles['BF_OPENEXR_INC'].split())
incs.extend(cycles['BF_PYTHON_INC'].split())

if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
    cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc'.split())
else:
    cxxflags.append('-ffast-math'.split())

# Warnings
# XXX Not supported by gcc < 4.9, since we do not have any 'supported flags' test as in cmake,
#     simpler to comment for now.
#if env['C_COMPILER_ID'] == 'gcc':
#    cxxflags.append(['-Werror=float-conversion'])

if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
    incs.append(env['BF_PTHREADS_INC'])

# optimized kernel. we compile the kernel multiple times with different
# optimization flags, at runtime it will choose the optimal kernel
kernel_flags = {}

if env['OURPLATFORM'] == 'win32-vc':
    # there is no /arch:SSE3, but intrinsics are available anyway
    kernel_flags['sse2'] = '/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /GS-'
    kernel_flags['sse3'] = kernel_flags['sse2']

elif env['OURPLATFORM'] == 'win64-vc':
    # /arch:AVX only available from visual studio 2012
    kernel_flags['sse2'] = '-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /GS-'
    kernel_flags['sse3'] = kernel_flags['sse2']

    if env['MSVC_VERSION'] >= '12.0':
        kernel_flags['sse41'] = kernel_flags['sse3']
        kernel_flags['avx'] = kernel_flags['sse41'] + ' /arch:AVX'
        kernel_flags['avx2'] = kernel_flags['sse41'] + ' /arch:AVX /arch:AVX2'
else:
    # -mavx only available with relatively new gcc/clang
    kernel_flags['sse2'] = '-ffast-math -msse -msse2 -mfpmath=sse'
    kernel_flags['sse3'] = kernel_flags['sse2'] + ' -msse3 -mssse3'
    kernel_flags['sse41'] = kernel_flags['sse3'] + ' -msse4.1'

    if (env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6') or (env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.1'):
        kernel_flags['avx'] = kernel_flags['sse41'] + ' -mavx'
        kernel_flags['avx2'] = kernel_flags['avx'] + ' -mavx2 -mfma -mlzcnt -mbmi -mbmi2'

for kernel_type in kernel_flags.keys():
    defs.append('WITH_KERNEL_' + kernel_type.upper())

for kernel_type in kernel_flags.keys():
    kernel_source = path.join('kernel', 'kernel_' + kernel_type + '.cpp')
    kernel_cxxflags = Split(env['CXXFLAGS'])
    kernel_cxxflags.append(kernel_flags[kernel_type].split())
    kernel_defs = defs[:]
    kernel_env = cycles.Clone()

    if env['OURPLATFORM'] == 'darwin' and env['C_COMPILER_ID'] == 'gcc' and  env['CCVERSION'] >= '4.6':
        # use Apple assembler for avx , gnu-compilers do not support it ( gnu gcc-4.6 or higher case )
        kernel_env.BlenderLib('bf_intern_cycles_' + kernel_type, [kernel_source], incs, kernel_defs,
            libtype=['intern'], priority=[10], cxx_compileflags=kernel_cxxflags,
            cc_compilerchange='/usr/bin/clang', cxx_compilerchange='/usr/bin/clang++')
    else:
        kernel_env.BlenderLib('bf_intern_cycles_' + kernel_type, [kernel_source], incs, kernel_defs,
            libtype=['intern'], priority=[10], cxx_compileflags=kernel_cxxflags)

cycles.BlenderLib('bf_intern_cycles', sources, incs, defs, libtype=['intern'], priority=[0], cxx_compileflags=cxxflags)

# OSL shaders
if env['WITH_BF_CYCLES_OSL']:
    oso_files = SConscript(['kernel/shaders/SConscript'])
    cycles.Depends("kernel/osl/osl_shader.o", oso_files)

    SConscript(['kernel/osl/SConscript'])

# cuda kernel binaries
if env['WITH_BF_CYCLES_CUDA_BINARIES']:
    kernel_binaries = SConscript(['kernel/SConscript'])
    cycles.Depends("device/device_cuda.o", kernel_binaries)

