#
# menger - visualization of the Menger sponge
# Copyright (C) 1995-2026  Joachim Reichel <joachim.reichel@posteo.de>
#
# 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.
#

# USE_DEBUG  := 1
# USE_CLANG  := 1
# USE_ASAN   := 1
# USE_LSAN   := 1
# USE_TSAN   := 1
# USE_UBSAN  := 1
# USE_OPENMP := 1
# USE_QT     := 1
# USE_GLEW   := 1
USE_PNG    := 1
# USE_JPEG   := 1
# USE_GTEST  := 1

CPPFLAGS   += -DMENGER_PACKAGE=\"$(NAME)\" -DMENGER_VERSION=\"$(VERSION)\"
ifdef USE_DEBUG
  CPPFLAGS += -g
else
  CPPFLAGS += -O3 -DNDEBUG
endif

CFLAGS     += $(CPPFLAGS) -std=c11
CFLAGS     += -Wall -Wextra -Wconversion -Wformat-security -Wno-unused-parameter
CXXFLAGS   += $(CPPFLAGS) -std=c++20
CXXFLAGS   += -Wall -Wextra -Wconversion -Wformat-security -Wold-style-cast
LDFLAGS    += -fuse-ld=mold

ifdef USE_CLANG
  CC       = clang
  CXX      = clang++
  CXXFLAGS += -Wno-sign-conversion
else
  CC       = gcc
  CXX      = g++
  CFLAGS   += -Wlogical-op
  CXXFLAGS += -Wlogical-op
endif

ifdef USE_ASAN
  CXXFLAGS += -fsanitize=address
  LDFLAGS  += -fsanitize=address
endif

ifdef USE_LSAN
  CXXFLAGS += -fsanitize=leak
  LDFLAGS  += -fsanitize=leak
endif

ifdef USE_TSAN
  CXXFLAGS += -fsanitize=thread
  LDFLAGS  += -fsanitize=thread
endif

ifdef USE_UBSAN
  CXXFLAGS += -fsanitize=undefined
  LDFLAGS  += -fsanitize=undefined
endif

ifdef USE_OPENMP
  CXXFLAGS += -fopenmp -DHAVE_OPENMP
  LDFLAGS  += -fopenmp
endif

ifdef USE_QT
  QT_MOC   = qtchooser -run-tool=moc -qt=5
  CXXFLAGS += -I/usr/include/qt5 -I/usr/include/x86_64-linux-gnu/qt5 -DHAVE_QT
  LDFLAGS  += -lQt5Widgets -lQt5Gui -lQt5OpenGL -lQt5Core -lGLU -lGL
endif

ifdef USE_GLEW
  CXXFLAGS += -DHAVE_GLEW
  LDFLAGS  += -lGLEW
endif

ifdef USE_PNG
  CXXFLAGS += -DHAVE_PNG
  LDFLAGS  += -lpng
endif

ifdef USE_JPEG
  CXXFLAGS += -DHAVE_JPEG
  LDFLAGS  += -ljpeg
endif

ifdef USE_GTEST
  CXXFLAGS += -DHAVE_GTEST
  LDFLAGS  += -lgtest -pthread
endif

LDFLAGS += -lvulkan -lglfw

CLANG_TIDY_CHECKS     = bugprone-*,cppcoreguidelines-*,misc-*,modernize-*,performance-*,readability-*
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-avoid-c-arrays
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-pro-bounds-array-to-pointer-decay
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-pro-bounds-constant-array-index
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-pro-bounds-pointer-arithmetic
CLANG_TIDY_EXCEPTIONS += -readability-braces-around-statements
CLANG_TIDY_EXCEPTIONS += -modernize-avoid-c-arrays
CLANG_TIDY_EXCEPTIONS += -modernize-use-trailing-return-type
CLANG_TIDY_EXCEPTIONS += -readability-else-after-return
CLANG_TIDY_EXCEPTIONS += -readability-implicit-bool-conversion
ifdef USE_GTEST
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-avoid-non-const-global-variables
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-owning-memory
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-pro-type-vararg
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-special-member-functions
endif
CLANG_TIDY_EXCEPTIONS += -bugprone-easily-swappable-parameters
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-avoid-magic-numbers
CLANG_TIDY_EXCEPTIONS += -cppcoreguidelines-pro-type-union-access
CLANG_TIDY_EXCEPTIONS += -misc-const-correctness
CLANG_TIDY_EXCEPTIONS += -misc-include-cleaner
CLANG_TIDY_EXCEPTIONS += -misc-non-private-member-variables-in-classes
CLANG_TIDY_EXCEPTIONS += -modernize-use-designated-initializers
CLANG_TIDY_EXCEPTIONS += -readability-identifier-length
CLANG_TIDY_EXCEPTIONS += -readability-magic-numbers
CLANG_TIDY_EXCEPTIONS += -readability-math-missing-parentheses

.SUFFIXES:

.SECONDARY:

.PHONY: default all check clean tarball

SOURCES_C = $(wildcard *.c)

SOURCES_CXX = $(wildcard *.cpp)

HEADERS = $(wildcard *.h)

CHECK_HEADERS = $(HEADERS)

TARGETS = \
  menger

OBJECTS = \
	  menger.cpp.o \
	  vulkan_base.cpp.o \
	  menger.frag.spv \
  menger.vert.spv

QUIET = $(if $(quiet),@echo "  $1	$(if $2,$2,$@)";,)
VERY_QUIET = $(if $(quiet),@,)

NULL  =
SPACE = $(NULL) #
COMMA = ,

default: $(TARGETS)

all: $(TARGETS) check

menger: $(OBJECTS)
	$(call QUIET,LD)$(CXX) -o $@ menger.cpp.o vulkan_base.cpp.o $(LDFLAGS)

vulkan_base.cpp.o: ../common/vulkan.cpp ../common/vulkan.h Makefile
	$(call QUIET,CXX)$(CXX) -o $@ -c ../common/vulkan.cpp $(CXXFLAGS) -MD -MF $@.d

%.c.o: %.c Makefile
	$(call QUIET,CC)$(CC) -o $@ -c $< $(CFLAGS) -MD -MF $@.d

%.cpp.o: %.cpp Makefile ../common/generator.h
	$(call QUIET,CXX)$(CXX) -o $@ -c $< $(CXXFLAGS) -MD -MF $@.d

%.spv: % Makefile
	$(call QUIET,GLSL)glslangValidator --target-env vulkan1.0 --quiet $< -o $@

%.moc.cpp: %.h
	$(QT_MOC) -o $@ $<

-include $(SOURCES_C:.c=.c.o.d)
-include $(SOURCES_CXX:.cpp=.cpp.o.d)

STANDALONE_HEADER_TEST_SOURCES := \
  $(addprefix test_standalone_header_, $(addsuffix .cpp, $(CHECK_HEADERS)))

MINMAX_HEADER_TEST_SOURCES := \
  $(addprefix test_minmax_header_, $(addsuffix .cpp, $(CHECK_HEADERS)))

$(STANDALONE_HEADER_TEST_SOURCES):test_standalone_header_%.cpp:
	@echo "#include <$*>" >$@

$(MINMAX_HEADER_TEST_SOURCES):test_minmax_header_%.cpp:
	@echo "#define min(a,b) dummy_min" > $@
	@echo "#define max(a,b) dummy_max" >>$@
	@echo "#include <$*>" >>$@

STANDALONE_HEADER_TEST_OBJECTS := $(STANDALONE_HEADER_TEST_SOURCES:.cpp=.o)

MINMAX_HEADER_TEST_OBJECTS := $(MINMAX_HEADER_TEST_SOURCES:.cpp=.o)

$(STANDALONE_HEADER_TEST_OBJECTS):%.o:%.cpp
	$(call QUIET,CXX)$(CXX) -o $@ -c $< $(CXXFLAGS) -I.
	$(call VERY_QUIET)rm -f $@ $<

$(MINMAX_HEADER_TEST_OBJECTS):%.o:%.cpp
	$(call QUIET,CXX)$(CXX) -o $@ -c $< $(CXXFLAGS) -I.
	$(call VERY_QUIET)rm -f $@ $<

check: default $(STANDALONE_HEADER_TEST_OBJECTS) $(MINMAX_HEADER_TEST_OBJECTS)

clean::
	rm -f test_standalone_header_* test_minmax_header_*

tidy:
	clang-tidy --checks=$(CLANG_TIDY_CHECKS),$(subst $(SPACE),$(COMMA),$(CLANG_TIDY_EXCEPTIONS)) $(wildcard *.cpp) -- \
    -I. -x c++ $(CXXFLAGS) >clang-tidy.out  || /bin/true
	grep -Eo "\[[a-zA-Z0-9\.,-]+\]" clang-tidy.out | grep -- - | sort | uniq -c | sort -n -r

clean::
	rm -f clang-tidy.out

clean::
	rm -f *~ *.o *.d $(TARGETS) *.moc.cpp *.spv
