###############################################################################
# Configure section
#
# Specify the compiler, some standard variables, and build options.
###############################################################################

#PREFIX ?= i686-w64-mingw32-
AR = $(PREFIX)ar
CC = $(PREFIX)gcc
CP = cp
LD = $(PREFIX)gcc
RANLIB = $(PREFIX)ranlib
STRIP = $(PREFIX)strip
YASM = yasm

CFLAGS = -Wall -Wextra -std=c99 $(DEPFLAGS) -I.
LDFLAGS = -L.
LIBS = -lavs
YASMFLAGS = -DHAVE_CPUNOP=1 -DHAVE_ALIGNED_STACK=1 -I.

CFLAGS_OPT = -O3 -fomit-frame-pointer

CFLAGS_OPT_X86 = -march=i686 -mmmx -msse -msse2 \
                 -ffast-math \

CFLAGS_OPT_X64 = -march=native -mmmx -msse -msse2 \
                 -ffast-math \

# Automatically generate dependency files.
# -MMD - only for local includes
# -MF  - file in which to write the rule
# -MT  - target of the rule
DEPFLAGS = -MMD -MF $(@:.o=.d) -MT $@

ARCH_X86 = 1
ARCH_X86_64 = 0
CONFIG_DEBUG = 1
CONFIG_LUA = 1
CONFIG_LUAJIT = 1
SYS_WINDOWS = 1

###############################################################################
# End of configure section.
###############################################################################

# x86_64 must imply x86 also.
ifeq ($(ARCH_X86_64),1)
    ARCH_X86 = 1
endif

# LuaJIT must imply Lua also.
ifeq ($(CONFIG_LUAJIT),1)
    CONFIG_LUA = 1
endif

ifeq ($(SYS_WINDOWS),1)
    # If on Windows the .exe extension is needed.
    EXE=.exe

    # Yasm needs different format flags if on Windows.
    ifeq ($(ARCH_X86_64),1)
        YASMFLAGS += -f win64 -m amd64
    else
        YASMFLAGS += -f win32 -m x86 -DPREFIX
    endif
else
    # Set the correct format flags for Yasm
    ifeq ($(ARCH_X86_64),1)
        YASMFLAGS += -f elf -m amd64
    else
        # TODO: check whether this needs -DPREFIX
        YASMFLAGS += -f elf -m x86
    endif
endif

ifeq ($(CONFIG_DEBUG),1)
    CFLAGS += -O0 -g
else
    # If not in debug mode then append the appropriate optimisation flags.
    # Also disable debug symbols from Yasm.
    CFLAGS += $(CFLAGS_OPT)
    YASMFLAGS += -g null

    # Append the platform specific optimisation flags.
    ifeq ($(ARCH_X86_64),1)
        CFLAGS += $(CFLAGS_OPT_X64)
    else ifeq ($(ARCH_X86),1)
        CFLAGS += $(CFLAGS_OPT_X86)
    endif
endif

ifeq ($(CONFIG_LUA),1)
    ifeq ($(CONFIG_LUAJIT),1)
        LIBS += -lluajit
    else
        LIBS += -llua
    endif
endif

$(foreach VAR, \
    ARCH_X86 ARCH_X86_64 CONFIG_DEBUG CONFIG_LUA CONFIG_LUAJIT SYS_WINDOWS, \
    $(eval CFLAGS += -D$(VAR)=$($(VAR))) \
    $(eval YASMFLAGS += -D$(VAR)=$($(VAR))) \
)

# Try some quiet rules
ifndef V
Q      = @
ECHO   = printf "$(1)\t%s\n" $(2)
BRIEF  = AR CC LD STRIP YASM
SILENT = CP RANLIB RM

MSG    = $@
M      = @$(call ECHO,$(TAG),$@);
$(foreach VAR,$(BRIEF), $(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
endif

# List of object files.

LIB_OBJECTS = bpm.o \
              block.o \
              components.o \
              effect_list.o \
              expressions.o \
              linedraw.o \
              main.o \
              matrix.o \
              not_implemented.o \
              pixel.o \
              utils.o \

MISC_OBJECTS = misc/buffer_save.o \
               misc/comment.o \
               misc/render_mode.o \

RENDER_OBJECTS = render/beat_clear.o \
                 render/bass_spin.o \
                 render/clear_screen.o \
                 render/dot_fountain.o \
                 render/dot_grid.o \
                 render/dot_plane.o \
                 render/osc_star.o \
                 render/particle.o \
                 render/ring.o \
                 render/rot_star.o \
                 render/simple.o \
                 render/superscope.o \
                 render/star_field.o \
                 render/timescope.o \

TRANS_OBJECTS = trans/blit.o \
                trans/blur.o \
                trans/brightness.o \
                trans/bump.o \
                trans/channel_shift.o \
                trans/colour_clip.o \
                trans/colour_fade.o \
                trans/colour_map.o \
                trans/colour_modifier.o \
                trans/colour_reduction.o \
                trans/dynamic_distance_modifier.o \
                trans/dynamic_movement.o \
                trans/dynamic_shift.o \
                trans/fadeout.o \
                trans/fast_brightness.o \
                trans/grain.o \
                trans/interferences.o \
                trans/interleave.o \
                trans/invert.o \
                trans/mirror.o \
                trans/mosaic.o \
                trans/movement.o \
                trans/multiplier.o \
                trans/roto_blit.o \
                trans/scatter.o \
                trans/texer.o \
                trans/unique_tone.o \
                trans/video_delay.o \
                trans/water.o \
                trans/water_bump.o \

X86_OBJECTS = x86/block.o \
              x86/channel_shift.o \
              x86/colour_reduction.o \
              x86/fast_brightness.o \
              x86/init.o \
              x86/multiplier.o \
              x86/unique_tone.o \
              x86/water.o \

LIB_OBJECTS += $(MISC_OBJECTS) $(RENDER_OBJECTS) $(TRANS_OBJECTS)

LIBRARY = libavs.a

PROGRAMS = tests/benchmark \
           tests/test \

X86_PROGRAMS = tests/asm_block \

ifeq ($(ARCH_X86),1)
    LIB_OBJECTS += $(X86_OBJECTS)
    PROGRAMS += $(X86_PROGRAMS)
endif

PROGRAMS := $(PROGRAMS:%=%$(EXE))

ALL_OBJECTS = $(LIB_OBJECTS) $(PROGRAMS:$(EXE)=.o)

# Targets

# When make is run without specifying a target on the command line, make will
# default to the first target written in the makefile.  The order of the
# dependencies is important because they get fulfilled left to right.
all: lib cli

# The target "cli" depends on the created programs and the library.  "lib" comes
# first otherwise make can attempt to link the programs before the library was
# made.
cli: $(PROGRAMS)

# The target "lib" depends on the created library.
lib: $(LIBRARY)

# Recipes

# The recipe to make the debug programs.  This has a dependency on lib to ensure
# that they are rebuilt when library objects change.
%_g$(EXE): %.o $(LIBRARY)
	$(LD) $(LDFLAGS) -o $@ $< $(LIBS)

# This "double dependency" stops make from automatically removing the
# intermediate files produced (the object files and the debug versions).
$(PROGRAMS): %$(EXE): %_g$(EXE)
	$(CP) $< $@
	$(STRIP) $@

# The recipe to make the library.
$(LIBRARY): $(LIB_OBJECTS)
	$(AR) rc $(LIBRARY) $(LIB_OBJECTS)
	$(RANLIB) $(LIBRARY)

# Recipe to make objects from assembly
%.o: %.asm x86/x86inc.asm x86/x86util.asm
	$(YASM) $(YASMFLAGS) -o $@ $<

# The use of the 'Q' command in sed here is a GNU extension.
lua-helper.h: doc/function-helper.lua doc/global-helper.lua doc/sanitize-helper.lua
	$(RM) $@
	echo 'static const char *lua_function_helper =' >> $@
	sed '/^--\[/Q;s|^\(.\+\)$$|"\1\\n"|' doc/function-helper.lua >> $@
	echo ';' >> $@
	echo 'static const char *lua_global_helper =' >> $@
	sed '/^--\[/Q;s|^\(.\+\)$$|"\1\\n"|' doc/global-helper.lua >> $@
	echo ';' >> $@
	echo 'static const char *lua_sanitize_helper =' >> $@
	sed '/^--\[/Q;s|^\(.\+\)$$|"\1\\n"|' doc/sanitize-helper.lua >> $@
	echo ';' >> $@

expressions.o: lua-helper.h

winamp: vis_jdavs.o lib
	$(LD) $(LDFLAGS) -mwindows -municode -mdll -o $(<:.o=.dll) $< $(LIBS) -lgdi32 -lcomdlg32
	$(CP) $(<:.o=.dll) /cygdrive/c/Winamp/Plugins/

# Use the built-in variable for rm
clean: clean-prof
	$(RM) $(ALL_OBJECTS:.o=.d)
	$(RM) $(ALL_OBJECTS)
	$(RM) $(LIBRARY) $(PROGRAMS) $(PROGRAMS:$(EXE)=_g$(EXE)) lua-helper.h

clean-prof:
	$(RM) $(ALL_OBJECTS:.o=.gcda)
	$(RM) $(ALL_OBJECTS:.o=.gcda.info)
	$(RM) $(ALL_OBJECTS:.o=.gcno)

.PHONY: all clean clean-prof cli lib winamp

-include $(ALL_OBJECTS:.o=.d)
