aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in617
-rw-r--r--src/chfb.cpp152
-rw-r--r--src/chfb.h28
-rw-r--r--src/config.h88
-rw-r--r--src/config.h.in87
-rw-r--r--src/main.cpp508
-rw-r--r--src/math_vector.cpp173
-rw-r--r--src/math_vector.h69
-rw-r--r--src/obj3d.cpp46
-rw-r--r--src/obj3d.h42
-rw-r--r--src/pixfb.cpp153
-rw-r--r--src/pixfb.h29
-rw-r--r--src/stamp-h11
-rw-r--r--src/tri_vertex.cpp314
-rw-r--r--src/tri_vertex.h29
-rw-r--r--src/vertex.cpp16
-rw-r--r--src/vertex.h25
-rw-r--r--src/vertex_data.cpp12
-rw-r--r--src/vertex_data.h12
20 files changed, 2403 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..99ac33d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,2 @@
+bin_PROGRAMS = main
+main_SOURCES = main.cpp math_vector.cpp chfb.cpp pixfb.cpp obj3d.cpp vertex_data.cpp vertex.cpp tri_vertex.cpp
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..c364a1f
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,617 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = main$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_main_OBJECTS = main.$(OBJEXT) math_vector.$(OBJEXT) chfb.$(OBJEXT) \
+ pixfb.$(OBJEXT) obj3d.$(OBJEXT) vertex_data.$(OBJEXT) \
+ vertex.$(OBJEXT) tri_vertex.$(OBJEXT)
+main_OBJECTS = $(am_main_OBJECTS)
+main_LDADD = $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/chfb.Po ./$(DEPDIR)/main.Po \
+ ./$(DEPDIR)/math_vector.Po ./$(DEPDIR)/obj3d.Po \
+ ./$(DEPDIR)/pixfb.Po ./$(DEPDIR)/tri_vertex.Po \
+ ./$(DEPDIR)/vertex.Po ./$(DEPDIR)/vertex_data.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(main_SOURCES)
+DIST_SOURCES = $(main_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+main_SOURCES = main.cpp math_vector.cpp chfb.cpp pixfb.cpp obj3d.cpp vertex_data.cpp vertex.cpp tri_vertex.cpp
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+main$(EXEEXT): $(main_OBJECTS) $(main_DEPENDENCIES) $(EXTRA_main_DEPENDENCIES)
+ @rm -f main$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(main_OBJECTS) $(main_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chfb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/math_vector.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj3d.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pixfb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tri_vertex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vertex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vertex_data.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) config.h
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/chfb.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/math_vector.Po
+ -rm -f ./$(DEPDIR)/obj3d.Po
+ -rm -f ./$(DEPDIR)/pixfb.Po
+ -rm -f ./$(DEPDIR)/tri_vertex.Po
+ -rm -f ./$(DEPDIR)/vertex.Po
+ -rm -f ./$(DEPDIR)/vertex_data.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/chfb.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/math_vector.Po
+ -rm -f ./$(DEPDIR)/obj3d.Po
+ -rm -f ./$(DEPDIR)/pixfb.Po
+ -rm -f ./$(DEPDIR)/tri_vertex.Po
+ -rm -f ./$(DEPDIR)/vertex.Po
+ -rm -f ./$(DEPDIR)/vertex_data.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/chfb.cpp b/src/chfb.cpp
new file mode 100644
index 0000000..249fb16
--- /dev/null
+++ b/src/chfb.cpp
@@ -0,0 +1,152 @@
+#include "chfb.h"
+#include <array>
+#include <cmath>
+#include <vector>
+#include "math_vector.h"
+#include "vertex.h"
+#include "tri_vertex.h"
+#include "vertex_data.h"
+
+CharacterFrameBuffer::CharacterFrameBuffer(unsigned int w, unsigned int h) {
+ resize(w, h);
+}
+
+void CharacterFrameBuffer::resize(unsigned int w, unsigned int h) {
+ this->w = w;
+ this->h = h;
+ chars_vector.resize(w * h);
+ depth_buf.resize(w * h);
+ clear();
+}
+
+unsigned int CharacterFrameBuffer::width() const {
+ return w;
+}
+
+unsigned int CharacterFrameBuffer::height() const {
+ return h;
+}
+
+const char* CharacterFrameBuffer::chars() const {
+ return chars_vector.data();
+}
+
+void CharacterFrameBuffer::clear() {
+ std::fill(chars_vector.begin(), chars_vector.end(), ' ');
+ std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
+ face_ind = -1;
+}
+
+void CharacterFrameBuffer::_draw_cropped_triangle(TriangleVertex3 triangle) {
+ std::array<Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
+
+#define SWAP_IF_LT(X,Y) ({\
+ if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
+ Vertex3* temp = sorted_vs[X];\
+ sorted_vs[X] = sorted_vs[Y];\
+ sorted_vs[Y] = temp;\
+ }\
+ })
+ SWAP_IF_LT(1, 0);
+ SWAP_IF_LT(2, 1);
+ SWAP_IF_LT(1, 0);
+#undef SWAP_IF_LT
+
+ Vertex3 middle_vl = *sorted_vs[1];
+ float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
+ Vertex3 middle_vr{
+ {
+ sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
+ sorted_vs[1]->point.y,
+ sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
+ },
+ VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
+ };
+ if (middle_vr.point.x < middle_vl.point.x) {
+ Vertex3 temp = middle_vr;
+ middle_vr = middle_vl;
+ middle_vl = temp;
+ }
+
+ // top triangle
+ {
+ if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
+ int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
+ int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
+ float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
+ float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[0]->point.z + s * (middle_vl.point.z - sorted_vs[0]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ chars_vector[x + y * w] = face_char();
+ }
+ }
+ }
+ }
+ }
+
+ // bottom triangle
+ {
+ if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
+ int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
+ int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
+ float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
+ float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[2]->point.z + s * (middle_vl.point.z - sorted_vs[2]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ chars_vector[x + y * w] = face_char();
+ }
+ }
+ }
+ }
+ }
+}
+
+void CharacterFrameBuffer::draw_triangle(TriangleVertex4 triangle) {
+ face_ind++;
+ for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
+ for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
+ MathVector2 pp1 = t2.vertex1.point.xy(),
+ pp2 = t2.vertex2.point.xy(),
+ pp3 = t2.vertex3.point.xy();
+ if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
+ t2.vertex1.point = (t2.vertex1.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex2.point = (t2.vertex2.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex3.point = (t2.vertex3.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ float fw = static_cast<float>(w), fh = static_cast<float>(h);
+ t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
+ t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
+ t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
+ t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
+ t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
+ t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
+ _draw_cropped_triangle(t2);
+ }
+ }
+}
+
+char CharacterFrameBuffer::face_char() const {
+ int n = 1 + face_ind / 2;
+ return (n < 10 ? '0' : 'A' - 10) + n;
+}
diff --git a/src/chfb.h b/src/chfb.h
new file mode 100644
index 0000000..66fd79c
--- /dev/null
+++ b/src/chfb.h
@@ -0,0 +1,28 @@
+#ifndef CHFB_H
+#define CHFB_H
+
+#include <vector>
+#include "math_vector.h"
+#include "tri_vertex.h"
+
+class CharacterFrameBuffer {
+ public:
+ CharacterFrameBuffer(unsigned int w, unsigned int h);
+ void resize(unsigned int w, unsigned int h);
+ unsigned int width() const;
+ unsigned int height() const;
+ const char* chars() const;
+ void clear();
+ void draw_triangle(TriangleVertex4 triangle);
+
+ private:
+ unsigned int w, h;
+ std::vector<char> chars_vector;
+ std::vector<float> depth_buf;
+ int face_ind;
+
+ void _draw_cropped_triangle(TriangleVertex3 triangle);
+ char face_char() const;
+};
+
+#endif // CHFB_H
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..c56505a
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,88 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Enable ncurses */
+#define ENABLE_NCURSES 0
+
+/* Define to 1 if you have the `floor' function. */
+/* #undef HAVE_FLOOR */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `SDL2' library (-lSDL2). */
+#define HAVE_LIBSDL2 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "engine"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "vincent.menegaux@gmail.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "engine"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "engine alpha"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "engine"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "alpha"
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "alpha"
+
+/* Linux OS */
+#define VIMENE_LINUX 0
+
+/* OS */
+#define VIMENE_OS VIMENE_LINUX
+
+/* Windows OS */
+#define VIMENE_WINDOWS 1
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..4e60460
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,87 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Enable ncurses */
+#undef ENABLE_NCURSES
+
+/* Define to 1 if you have the `floor' function. */
+#undef HAVE_FLOOR
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `SDL2' library (-lSDL2). */
+#undef HAVE_LIBSDL2
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Linux OS */
+#undef VIMENE_LINUX
+
+/* OS */
+#undef VIMENE_OS
+
+/* Windows OS */
+#undef VIMENE_WINDOWS
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..c246491
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,508 @@
+#include "config.h"
+#include <iostream>
+
+//#include <ncurses.h>
+
+#if VIMENE_OS==VIMENE_WINDOWS
+#include <windows.h>
+#endif
+
+#include <cmath>
+#include <cstdint>
+#include <vector>
+#include <SDL2/SDL.h>
+#include "chfb.h"
+#include "pixfb.h"
+#include "obj3d.h"
+#include "math_vector.h"
+#include "vertex.h"
+#include "vertex_data.h"
+#include "tri_vertex.h"
+
+#define MKEY_Z 122
+#define MKEY_Q 113
+#define MKEY_S 115
+#define MKEY_D 100
+
+#define MKEY_ESC 27
+
+#define FPS 60
+
+#define PI 3.1415926535f
+
+#if ENABLE_NCURSES==1
+void main_term() {
+ // init
+ setlocale(LC_ALL, "");
+ initscr();
+ cbreak();
+ noecho();
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ set_escdelay(0);
+ curs_set(0);
+
+ int w, h;
+ getmaxyx(stdscr, h, w);
+ CharacterFrameBuffer cfb{static_cast<unsigned int>(w), static_cast<unsigned int>(h)};
+
+ MathVector3 a{0.f, 0.f, 0.f};
+ float dist = 4.f;
+ while (1) {
+ //timeout(1000 / FPS);
+ timeout(10);
+ int c = getch();
+
+ if (c == MKEY_ESC) break;
+ switch (c) {
+ case KEY_UP:
+ // a.x += 0.1f;
+ dist += .1f;
+ break;
+ case KEY_DOWN:
+ // a.x -= 0.1f;
+ dist -= .1f;
+ break;
+ case KEY_LEFT:
+ // a.y += 0.1f;
+ break;
+ case KEY_RIGHT:
+ // a.y -= 0.1f;
+ break;
+ case MKEY_Q:
+ // a.z += 0.1f;
+ break;
+ case MKEY_D:
+ // a.z -= 0.1f;
+ break;
+ }
+
+ a.x += .0050f;
+ a.y += .0065f;
+ a.z += .0080f;
+
+ getmaxyx(stdscr, h, w);
+ cfb.resize(static_cast<unsigned int>(w), static_cast<unsigned int>(h));
+
+ float rad = 5.f;
+ MathVector3 ca{std::cos(a.x), std::cos(a.y), std::cos(a.z)};
+ MathVector3 sa{std::sin(a.x), std::sin(a.y), std::sin(a.z)};
+
+ std::array<MathVector3, 3> rot_x = {{
+ { 1.f, 0.f, 0.f },
+ { 0.f, ca.x, sa.x },
+ { 0.f, -sa.x, ca.x },
+ }};
+ std::array<MathVector3, 3> rot_y = {{
+ { ca.y, 0.f, -sa.y },
+ { 0.f, 1.f, 0.f },
+ { sa.y, 0.f, ca.y },
+ }};
+ std::array<MathVector3, 3> rot_z = {{
+ { ca.z, sa.z, 0.f },
+ { -sa.z, ca.z, 0.f },
+ { 0.f, 0.f, 1.f },
+ }};
+
+ auto [e_x, e_y, e_z] = rot_x;
+ e_x = e_x.x * rot_y[0] + e_x.y * rot_y[1] + e_x.z * rot_y[2];
+ e_y = e_y.x * rot_y[0] + e_y.y * rot_y[1] + e_y.z * rot_y[2];
+ e_z = e_z.x * rot_y[0] + e_z.y * rot_y[1] + e_z.z * rot_y[2];
+ e_x = e_x.x * rot_z[0] + e_x.y * rot_z[1] + e_x.z * rot_z[2];
+ e_y = e_y.x * rot_z[0] + e_y.y * rot_z[1] + e_y.z * rot_z[2];
+ e_z = e_z.x * rot_z[0] + e_z.y * rot_z[1] + e_z.z * rot_z[2];
+
+ std::array<Object3D, 2> objs{{
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ },
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ }
+ }};
+ cfb.clear();
+ float min_z = 2.f, max_z = 50.f;
+ float fac_for_aspect_ratio = 2.f * static_cast<float>(cfb.height()) / static_cast<float>(cfb.width());
+ for (auto obj : objs) {
+ for (auto triangle : obj) {
+ TriangleVertex4 t{triangle};
+
+ // should be multiplied by a matrix, temporary replacement
+ t.vertex1.point.x *= fac_for_aspect_ratio;
+ t.vertex1.point.y = -t.vertex1.point.y;
+ t.vertex1.point.w = -t.vertex1.point.z;
+ t.vertex1.point.z = 2.f * (-t.vertex1.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex2.point.x *= fac_for_aspect_ratio;
+ t.vertex2.point.y = -t.vertex2.point.y;
+ t.vertex2.point.w = -t.vertex2.point.z;
+ t.vertex2.point.z = 2.f * (-t.vertex2.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex3.point.x *= fac_for_aspect_ratio;
+ t.vertex3.point.y = -t.vertex3.point.y;
+ t.vertex3.point.w = -t.vertex3.point.z;
+ t.vertex3.point.z = 2.f * (-t.vertex3.point.z - min_z) / (max_z - min_z) - 1.f;
+
+ cfb.draw_triangle(t);
+ }
+ }
+ mvaddnstr(0, 0, cfb.chars(), cfb.width() * cfb.height());
+ }
+
+ // terminate
+ endwin();
+}
+#endif
+
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 480
+
+void main_SDL() {
+ SDL_Window* window = NULL;
+ SDL_Renderer* renderer = NULL;
+ SDL_Texture* texture = NULL;
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ fprintf(stderr, "Error: SDL_Init error: %s\n", SDL_GetError());
+ return;
+ }
+ window = SDL_CreateWindow("Engine", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
+ if (window == NULL) {
+ fprintf(stderr, "Error: SDL_CreateWindow error: %s\n", SDL_GetError());
+ return;
+ }
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+ texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
+ PixelFrameBuffer pfb{SCREEN_WIDTH, SCREEN_HEIGHT};
+
+ MathVector3 a{0.f, 0.f, 0.f};
+ float dist = 4.f;
+ SDL_Event e;
+ bool quit = false;
+ while (!quit) {
+ a.x += .0050f;
+ a.y += .0065f;
+ a.z += .0080f;
+
+ float rad = 5.f;
+ MathVector3 ca{std::cos(a.x), std::cos(a.y), std::cos(a.z)};
+ MathVector3 sa{std::sin(a.x), std::sin(a.y), std::sin(a.z)};
+
+ std::array<MathVector3, 3> rot_x = {{
+ { 1.f, 0.f, 0.f },
+ { 0.f, ca.x, sa.x },
+ { 0.f, -sa.x, ca.x },
+ }};
+ std::array<MathVector3, 3> rot_y = {{
+ { ca.y, 0.f, -sa.y },
+ { 0.f, 1.f, 0.f },
+ { sa.y, 0.f, ca.y },
+ }};
+ std::array<MathVector3, 3> rot_z = {{
+ { ca.z, sa.z, 0.f },
+ { -sa.z, ca.z, 0.f },
+ { 0.f, 0.f, 1.f },
+ }};
+
+ auto [e_x, e_y, e_z] = rot_x;
+ e_x = e_x.x * rot_y[0] + e_x.y * rot_y[1] + e_x.z * rot_y[2];
+ e_y = e_y.x * rot_y[0] + e_y.y * rot_y[1] + e_y.z * rot_y[2];
+ e_z = e_z.x * rot_y[0] + e_z.y * rot_y[1] + e_z.z * rot_y[2];
+ e_x = e_x.x * rot_z[0] + e_x.y * rot_z[1] + e_x.z * rot_z[2];
+ e_y = e_y.x * rot_z[0] + e_y.y * rot_z[1] + e_y.z * rot_z[2];
+ e_z = e_z.x * rot_z[0] + e_z.y * rot_z[1] + e_z.z * rot_z[2];
+
+ std::array<Object3D, 2> objs{{
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ },
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ }
+ }};
+ pfb.clear();
+ float min_z = 2.f, max_z = 50.f;
+ float fac_for_aspect_ratio = 2.f * static_cast<float>(pfb.height()) / static_cast<float>(pfb.width());
+ for (auto obj : objs) {
+ for (auto triangle : obj) {
+ TriangleVertex4 t{triangle};
+
+ // should be multiplied by a matrix, temporary replacement
+ t.vertex1.point.x *= fac_for_aspect_ratio;
+ t.vertex1.point.y = -t.vertex1.point.y;
+ t.vertex1.point.w = -t.vertex1.point.z;
+ t.vertex1.point.z = 2.f * (-t.vertex1.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex2.point.x *= fac_for_aspect_ratio;
+ t.vertex2.point.y = -t.vertex2.point.y;
+ t.vertex2.point.w = -t.vertex2.point.z;
+ t.vertex2.point.z = 2.f * (-t.vertex2.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex3.point.x *= fac_for_aspect_ratio;
+ t.vertex3.point.y = -t.vertex3.point.y;
+ t.vertex3.point.w = -t.vertex3.point.z;
+ t.vertex3.point.z = 2.f * (-t.vertex3.point.z - min_z) / (max_z - min_z) - 1.f;
+
+ pfb.draw_triangle(t);
+ }
+ }
+ SDL_UpdateTexture(texture, NULL, pfb.pixels(), SCREEN_WIDTH * 4);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, texture, NULL, NULL);
+ SDL_RenderPresent(renderer);
+ SDL_UpdateWindowSurface(window);
+ while (SDL_WaitEventTimeout(&e, 10)) {
+ if (e.type == SDL_QUIT) {
+ quit = true;
+ }
+ }
+ }
+ SDL_DestroyTexture(texture);
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+}
+
+#if VIMENE_OS==VIMENE_LINUX
+int main(int argc, char *argv[]) {
+ (void) argc;
+ (void) argv;
+#elif VIMENE_OS==VIMENE_WINDOWS
+int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
+#endif
+ // main_term();
+ main_SDL();
+#if VIMENE_OS==VIMENE_LINUX
+ return EXIT_SUCCESS;
+#elif VIMENE_OS==VIMENE_WINDOWS
+ return 0;
+#endif
+}
diff --git a/src/math_vector.cpp b/src/math_vector.cpp
new file mode 100644
index 0000000..60081bf
--- /dev/null
+++ b/src/math_vector.cpp
@@ -0,0 +1,173 @@
+#include "math_vector.h"
+#include <cmath>
+
+MathVector2::MathVector2() {
+}
+
+MathVector2::MathVector2(float x, float y) : x{x}, y{y} {
+}
+
+bool MathVector2::operator==(MathVector2 other) const {
+ return x == other.x && y == other.y;
+}
+
+bool MathVector2::operator!=(MathVector2 other) const {
+ return !(*this == other);
+}
+
+MathVector2 MathVector2::operator+() const {
+ return *this;
+}
+
+MathVector2 MathVector2::operator-() const {
+ return { -x, -y };
+}
+
+MathVector2 MathVector2::operator+(MathVector2 other) const {
+ return { x + other.x, y + other.y };
+}
+
+MathVector2 MathVector2::operator-(MathVector2 other) const {
+ return *this + (-other);
+}
+
+float MathVector2::det(MathVector2 other) const {
+ return this->x * other.y - other.x * this->y;
+}
+
+MathVector2 MathVector2::round() const {
+ return { std::round(x), std::round(y) };
+}
+
+MathVector2 operator*(float n, MathVector2 other) {
+ return { n * other.x, n * other.y };
+}
+
+MathVector2 operator*(MathVector2 other, float n) {
+ return n * other;
+}
+
+MathVector2 operator/(MathVector2 other, float n) {
+ return { other.x / n, other.y / n };
+}
+
+MathVector3::MathVector3() {
+}
+
+MathVector3::MathVector3(float x, float y, float z) : x{x}, y{y}, z{z} {
+}
+
+bool MathVector3::operator==(MathVector3 other) const {
+ return x == other.x && y == other.y && z == other.z;
+}
+
+bool MathVector3::operator!=(MathVector3 other) const {
+ return !(*this == other);
+}
+
+MathVector3 MathVector3::operator+() const {
+ return *this;
+}
+
+MathVector3 MathVector3::operator-() const {
+ return { -x, -y, -z };
+}
+
+MathVector3 MathVector3::operator+(MathVector3 other) const {
+ return { x + other.x, y + other.y, z + other.z };
+}
+
+MathVector3 MathVector3::operator-(MathVector3 other) const {
+ return *this + (-other);
+}
+
+MathVector3 MathVector3::round() const {
+ return { std::round(x), std::round(y), std::round(z) };
+}
+
+MathVector2 MathVector3::xy() const {
+ return { x, y };
+}
+
+MathVector3 MathVector3::cross(MathVector3 other) const {
+ return {
+ y * other.z - z * other.y,
+ z * other.x - x * other.z,
+ x * other.y - y * other.x
+ };
+}
+
+MathVector3 operator*(float n, MathVector3 other) {
+ return { n * other.x, n * other.y, n * other.z };
+}
+
+MathVector3 operator*(MathVector3 other, float n) {
+ return n * other;
+}
+
+MathVector3 operator/(MathVector3 other, float n) {
+ return { other.x / n, other.y / n, other.z / n };
+}
+
+MathVector4::MathVector4() {
+}
+
+MathVector4::MathVector4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {
+}
+
+MathVector4::MathVector4(float x, float y, float z) : x{x}, y{y}, z{z}, w{1.f} {
+}
+
+MathVector4::MathVector4(MathVector3 v, float w) : x{v.x}, y{v.y}, z{v.z}, w{w} {
+}
+
+MathVector4::MathVector4(MathVector3 v) : x{v.x}, y{v.y}, z{v.z}, w{1.f} {
+}
+
+bool MathVector4::operator==(MathVector4 other) const {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+}
+
+bool MathVector4::operator!=(MathVector4 other) const {
+ return !(*this == other);
+}
+
+MathVector4 MathVector4::operator+() const {
+ return *this;
+}
+
+MathVector4 MathVector4::operator-() const {
+ return { -x, -y, -z, -w };
+}
+
+MathVector4 MathVector4::operator+(MathVector4 other) const {
+ return { x + other.x, y + other.y, z + other.z, w + other.w };
+}
+
+MathVector4 MathVector4::operator-(MathVector4 other) const {
+ return *this + (-other);
+}
+
+MathVector4 MathVector4::round() const {
+ return { std::round(x), std::round(y), std::round(z), std::round(w) };
+}
+
+MathVector3 MathVector4::xyz() const {
+ return { x, y, z };
+}
+
+MathVector3 MathVector4::div_by_w() const {
+ return xyz() / w;
+}
+
+MathVector4 operator*(float n, MathVector4 other) {
+ return { n * other.x, n * other.y, n * other.z, n * other.w };
+}
+
+MathVector4 operator*(MathVector4 other, float n) {
+ return n * other;
+}
+
+MathVector4 operator/(MathVector4 other, float n) {
+ return { other.x / n, other.y / n, other.z / n, other.w / n };
+}
diff --git a/src/math_vector.h b/src/math_vector.h
new file mode 100644
index 0000000..336c3fe
--- /dev/null
+++ b/src/math_vector.h
@@ -0,0 +1,69 @@
+#ifndef MATH_VECTOR_H
+#define MATH_VECTOR_H
+
+class MathVector2 {
+ public:
+ float x, y;
+
+ MathVector2();
+ MathVector2(float x, float y);
+ bool operator==(MathVector2 other) const;
+ bool operator!=(MathVector2 other) const;
+ MathVector2 operator+() const;
+ MathVector2 operator-() const;
+ MathVector2 operator+(MathVector2 other) const;
+ MathVector2 operator-(MathVector2 other) const;
+ float det(MathVector2 other) const;
+ MathVector2 round() const;
+};
+
+MathVector2 operator*(float n, MathVector2 other);
+MathVector2 operator*(MathVector2 other, float n);
+MathVector2 operator/(MathVector2 other, float n);
+
+class MathVector3 {
+ public:
+ float x, y, z;
+
+ MathVector3();
+ MathVector3(float x, float y, float z);
+ bool operator==(MathVector3 other) const;
+ bool operator!=(MathVector3 other) const;
+ MathVector3 operator+() const;
+ MathVector3 operator-() const;
+ MathVector3 operator+(MathVector3 other) const;
+ MathVector3 operator-(MathVector3 other) const;
+ MathVector3 round() const;
+ MathVector2 xy() const;
+ MathVector3 cross(MathVector3 other) const;
+};
+
+MathVector3 operator*(float n, MathVector3 other);
+MathVector3 operator*(MathVector3 other, float n);
+MathVector3 operator/(MathVector3 other, float n);
+
+class MathVector4 {
+ public:
+ float x, y, z, w;
+
+ MathVector4();
+ MathVector4(float x, float y, float z, float w);
+ MathVector4(float x, float y, float z);
+ MathVector4(MathVector3 v, float w);
+ MathVector4(MathVector3 v);
+ bool operator==(MathVector4 other) const;
+ bool operator!=(MathVector4 other) const;
+ MathVector4 operator+() const;
+ MathVector4 operator-() const;
+ MathVector4 operator+(MathVector4 other) const;
+ MathVector4 operator-(MathVector4 other) const;
+ MathVector4 round() const;
+ MathVector3 xyz() const;
+ MathVector3 div_by_w() const;
+};
+
+MathVector4 operator*(float n, MathVector4 other);
+MathVector4 operator*(MathVector4 other, float n);
+MathVector4 operator/(MathVector4 other, float n);
+
+#endif // MATH_VECTOR_H
diff --git a/src/obj3d.cpp b/src/obj3d.cpp
new file mode 100644
index 0000000..3902d30
--- /dev/null
+++ b/src/obj3d.cpp
@@ -0,0 +1,46 @@
+#include "obj3d.h"
+#include <vector>
+#include <array>
+#include "vertex.h"
+#include "tri_vertex.h"
+
+Object3D::TriangleVertex3Iterator::TriangleVertex3Iterator(const Object3D* obj, int face_ind) : obj{obj}, face_ind{face_ind} {
+}
+
+Object3D::TriangleVertex3Iterator& Object3D::TriangleVertex3Iterator::operator++() {
+ face_ind++;
+ return *this;
+}
+
+Object3D::TriangleVertex3Iterator Object3D::TriangleVertex3Iterator::operator++(int) {
+ TriangleVertex3Iterator retval = *this;
+ ++(*this);
+ return retval;
+}
+
+bool Object3D::TriangleVertex3Iterator::operator==(TriangleVertex3Iterator other) const {
+ return obj == other.obj && face_ind == other.face_ind;
+}
+
+bool Object3D::TriangleVertex3Iterator::operator!=(TriangleVertex3Iterator other) const {
+ return !(*this == other);
+}
+
+Object3D::TriangleVertex3Iterator::reference Object3D::TriangleVertex3Iterator::operator*() const {
+ return {
+ obj->pts[obj->faces[face_ind][0]],
+ obj->pts[obj->faces[face_ind][1]],
+ obj->pts[obj->faces[face_ind][2]]
+ };
+}
+
+Object3D::Object3D(std::vector<Vertex3> pts, std::vector<std::array<int, 3>> faces) : pts{pts}, faces{faces} {
+}
+
+Object3D::TriangleVertex3Iterator Object3D::begin() {
+ return Object3D::TriangleVertex3Iterator{this};
+}
+
+Object3D::TriangleVertex3Iterator Object3D::end() {
+ return Object3D::TriangleVertex3Iterator{this, static_cast<int>(faces.size())};
+}
diff --git a/src/obj3d.h b/src/obj3d.h
new file mode 100644
index 0000000..b76f06d
--- /dev/null
+++ b/src/obj3d.h
@@ -0,0 +1,42 @@
+#ifndef OBJ3D_H
+#define OBJ3D_H
+
+#include <vector>
+#include <array>
+#include <iterator>
+#include "vertex.h"
+#include "tri_vertex.h"
+
+class Object3D {
+ public:
+ class TriangleVertex3Iterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = TriangleVertex3;
+ using difference_type = TriangleVertex3;
+ using pointer = const TriangleVertex3*;
+ using reference = TriangleVertex3;
+
+ explicit TriangleVertex3Iterator(const Object3D* obj, int face_ind = 0);
+ TriangleVertex3Iterator& operator++();
+ TriangleVertex3Iterator operator++(int);
+ bool operator==(TriangleVertex3Iterator other) const;
+ bool operator!=(TriangleVertex3Iterator other) const;
+ reference operator*() const;
+
+ private:
+ const Object3D* obj;
+ int face_ind;
+
+ };
+
+ Object3D(std::vector<Vertex3> pts, std::vector<std::array<int, 3>> faces);
+ TriangleVertex3Iterator begin();
+ TriangleVertex3Iterator end();
+
+ private:
+ std::vector<Vertex3> pts;
+ std::vector<std::array<int, 3>> faces;
+};
+
+#endif // OBJ3D_H
diff --git a/src/pixfb.cpp b/src/pixfb.cpp
new file mode 100644
index 0000000..f84bf2f
--- /dev/null
+++ b/src/pixfb.cpp
@@ -0,0 +1,153 @@
+#include "pixfb.h"
+#include <array>
+#include <cmath>
+#include <vector>
+#include <cstdint>
+#include "math_vector.h"
+#include "vertex.h"
+#include "tri_vertex.h"
+#include "vertex_data.h"
+
+PixelFrameBuffer::PixelFrameBuffer(unsigned int w, unsigned int h) {
+ resize(w, h);
+}
+
+void PixelFrameBuffer::resize(unsigned int w, unsigned int h) {
+ this->w = w;
+ this->h = h;
+ pixels_vector.resize(w * h);
+ depth_buf.resize(w * h);
+ clear();
+}
+
+unsigned int PixelFrameBuffer::width() const {
+ return w;
+}
+
+unsigned int PixelFrameBuffer::height() const {
+ return h;
+}
+
+const uint32_t* PixelFrameBuffer::pixels() const {
+ return pixels_vector.data();
+}
+
+void PixelFrameBuffer::clear() {
+ std::fill(pixels_vector.begin(), pixels_vector.end(), 0x000000FF);
+ std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
+ face_ind = -1;
+}
+
+void PixelFrameBuffer::_draw_cropped_triangle(TriangleVertex3 triangle) {
+ std::array<Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
+
+#define SWAP_IF_LT(X,Y) ({\
+ if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
+ Vertex3* temp = sorted_vs[X];\
+ sorted_vs[X] = sorted_vs[Y];\
+ sorted_vs[Y] = temp;\
+ }\
+ })
+ SWAP_IF_LT(1, 0);
+ SWAP_IF_LT(2, 1);
+ SWAP_IF_LT(1, 0);
+#undef SWAP_IF_LT
+
+ Vertex3 middle_vl = *sorted_vs[1];
+ float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
+ Vertex3 middle_vr{
+ {
+ sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
+ sorted_vs[1]->point.y,
+ sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
+ },
+ VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
+ };
+ if (middle_vr.point.x < middle_vl.point.x) {
+ Vertex3 temp = middle_vr;
+ middle_vr = middle_vl;
+ middle_vl = temp;
+ }
+
+ // top triangle
+ {
+ if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
+ int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
+ int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
+ float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
+ float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[0]->point.z + s * (middle_vl.point.z - sorted_vs[0]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ pixels_vector[x + y * w] = face_color();
+ }
+ }
+ }
+ }
+ }
+
+ // bottom triangle
+ {
+ if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
+ int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
+ int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
+ float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
+ float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[2]->point.z + s * (middle_vl.point.z - sorted_vs[2]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ pixels_vector[x + y * w] = face_color();
+ }
+ }
+ }
+ }
+ }
+}
+
+void PixelFrameBuffer::draw_triangle(TriangleVertex4 triangle) {
+ face_ind++;
+ for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
+ for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
+ MathVector2 pp1 = t2.vertex1.point.xy(),
+ pp2 = t2.vertex2.point.xy(),
+ pp3 = t2.vertex3.point.xy();
+ if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
+ t2.vertex1.point = (t2.vertex1.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex2.point = (t2.vertex2.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex3.point = (t2.vertex3.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ float fw = static_cast<float>(w), fh = static_cast<float>(h);
+ t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
+ t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
+ t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
+ t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
+ t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
+ t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
+ _draw_cropped_triangle(t2);
+ }
+ }
+}
+
+uint32_t PixelFrameBuffer::face_color() const {
+ int n = face_ind / 2;
+ return ((n % 2 ? 0xFF000000 : 0x55000000) >> ((n % 6) / 2 * 8)) | 0xFF;
+}
diff --git a/src/pixfb.h b/src/pixfb.h
new file mode 100644
index 0000000..c54b5fb
--- /dev/null
+++ b/src/pixfb.h
@@ -0,0 +1,29 @@
+#ifndef PIXFB_H
+#define PIXFB_H
+
+#include <vector>
+#include <cstdint>
+#include "math_vector.h"
+#include "tri_vertex.h"
+
+class PixelFrameBuffer {
+ public:
+ PixelFrameBuffer(unsigned int w, unsigned int h);
+ void resize(unsigned int w, unsigned int h);
+ unsigned int width() const;
+ unsigned int height() const;
+ const uint32_t* pixels() const;
+ void clear();
+ void draw_triangle(TriangleVertex4 triangle);
+
+ private:
+ unsigned int w, h;
+ std::vector<uint32_t> pixels_vector;
+ std::vector<float> depth_buf;
+ int face_ind;
+
+ void _draw_cropped_triangle(TriangleVertex3 triangle);
+ uint32_t face_color() const;
+};
+
+#endif // PIXFB_H
diff --git a/src/stamp-h1 b/src/stamp-h1
new file mode 100644
index 0000000..57ea58e
--- /dev/null
+++ b/src/stamp-h1
@@ -0,0 +1 @@
+timestamp for src/config.h
diff --git a/src/tri_vertex.cpp b/src/tri_vertex.cpp
new file mode 100644
index 0000000..cd07770
--- /dev/null
+++ b/src/tri_vertex.cpp
@@ -0,0 +1,314 @@
+#include "tri_vertex.h"
+#include <vector>
+#include "math_vector.h"
+#include "vertex_data.h"
+#include "vertex.h"
+#include "tri_vertex.h"
+
+TriangleVertex3::TriangleVertex3(Vertex3 vertex1, Vertex3 vertex2, Vertex3 vertex3) : vertex1{vertex1}, vertex2{vertex2}, vertex3{vertex3} {
+}
+
+#define P1_OUT 1
+#define P2_OUT 2
+#define P3_OUT 4
+static void _crop_x(std::vector<TriangleVertex3>& tris, TriangleVertex3 t, int n, float x) {
+ switch (n) {
+ case 0:
+ tris.push_back(t);
+ break;
+ case P1_OUT:
+ case P2_OUT:
+ case P3_OUT:
+ case P2_OUT | P3_OUT:
+ case P1_OUT | P3_OUT:
+ case P1_OUT | P2_OUT:
+ {
+ Vertex3* q1;
+ Vertex3* q2;
+ Vertex3* q3;
+ switch (n) {
+ case P1_OUT:
+ case P2_OUT | P3_OUT:
+ q1 = &t.vertex1;
+ q2 = &t.vertex2;
+ q3 = &t.vertex3;
+ break;
+ case P2_OUT:
+ case P1_OUT | P3_OUT:
+ q1 = &t.vertex2;
+ q2 = &t.vertex1;
+ q3 = &t.vertex3;
+ break;
+ case P3_OUT:
+ case P1_OUT | P2_OUT:
+ q1 = &t.vertex3;
+ q2 = &t.vertex2;
+ q3 = &t.vertex1;
+ break;
+ }
+ MathVector3 dq2 = q1->point - q2->point;
+ float fac2 = (x - q2->point.x) / dq2.x;
+ Vertex3 r2{
+ {
+ x,
+ q2->point.y + fac2 * dq2.y,
+ q2->point.z + fac2 * dq2.z
+ },
+ VertexData::lerp(q2->data, q1->data, fac2)
+ };
+ MathVector3 dq3 = q1->point - q3->point;
+ float fac3 = (x - q3->point.x) / dq3.x;
+ Vertex3 r3{
+ {
+ x,
+ q3->point.y + fac3 * dq3.y,
+ q3->point.z + fac3 * dq3.z
+ },
+ VertexData::lerp(q3->data, q1->data, fac3)
+ };
+ switch (n) {
+ case P1_OUT:
+ tris.push_back({r3, *q2, *q3});
+ tris.push_back({r3, r2, *q2});
+ break;
+ case P2_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P3_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P2_OUT | P3_OUT:
+ tris.push_back({*q1, r2, r3});
+ break;
+ case P1_OUT | P3_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ case P1_OUT | P2_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ }
+ }
+ break;
+ case P1_OUT | P2_OUT | P3_OUT:
+ break;
+ }
+}
+
+static void _crop_y(std::vector<TriangleVertex3>& tris, TriangleVertex3 t, int n, float y) {
+ switch (n) {
+ case 0:
+ tris.push_back(t);
+ break;
+ case P1_OUT:
+ case P2_OUT:
+ case P3_OUT:
+ case P2_OUT | P3_OUT:
+ case P1_OUT | P3_OUT:
+ case P1_OUT | P2_OUT:
+ {
+ Vertex3* q1;
+ Vertex3* q2;
+ Vertex3* q3;
+ switch (n) {
+ case P1_OUT:
+ case P2_OUT | P3_OUT:
+ q1 = &t.vertex1;
+ q2 = &t.vertex2;
+ q3 = &t.vertex3;
+ break;
+ case P2_OUT:
+ case P1_OUT | P3_OUT:
+ q1 = &t.vertex2;
+ q2 = &t.vertex1;
+ q3 = &t.vertex3;
+ break;
+ case P3_OUT:
+ case P1_OUT | P2_OUT:
+ q1 = &t.vertex3;
+ q2 = &t.vertex2;
+ q3 = &t.vertex1;
+ break;
+ }
+ MathVector3 dq2 = q1->point - q2->point;
+ float fac2 = (y - q2->point.y) / dq2.y;
+ Vertex3 r2{
+ {
+ q2->point.x + fac2 * dq2.x,
+ y,
+ q2->point.z + fac2 * dq2.z
+ },
+ VertexData::lerp(q2->data, q1->data, fac2)
+ };
+ MathVector3 dq3 = q1->point - q3->point;
+ float fac3 = (y - q3->point.y) / dq3.y;
+ Vertex3 r3{
+ {
+ q3->point.x + fac3 * dq3.x,
+ y,
+ q3->point.z + fac3 * dq3.z
+ },
+ VertexData::lerp(q3->data, q1->data, fac3)
+ };
+ switch (n) {
+ case P1_OUT:
+ tris.push_back({r3, *q2, *q3});
+ tris.push_back({r3, r2, *q2});
+ break;
+ case P2_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P3_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P2_OUT | P3_OUT:
+ tris.push_back({*q1, r2, r3});
+ break;
+ case P1_OUT | P3_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ case P1_OUT | P2_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ }
+ }
+ break;
+ case P1_OUT | P2_OUT | P3_OUT:
+ break;
+ }
+}
+
+std::vector<TriangleVertex3> TriangleVertex3::crop_xy_out(float x1, float x2, float y1, float y2) const {
+ std::vector<TriangleVertex3> tris_final;
+ std::vector<TriangleVertex3> tris1;
+ _crop_x(tris1, *this, (vertex1.point.x < x1) | ((vertex2.point.x < x1) << 1) | ((vertex3.point.x < x1) << 2), x1);
+ for (auto t1 : tris1) {
+ std::vector<TriangleVertex3> tris2;
+ _crop_x(tris2, t1, (t1.vertex1.point.x > x2) | ((t1.vertex2.point.x > x2) << 1) | ((t1.vertex3.point.x > x2) << 2), x2);
+ for (auto t2 : tris2) {
+ std::vector<TriangleVertex3> tris3;
+ _crop_y(tris3, t2, (t2.vertex1.point.y < y1) | ((t2.vertex2.point.y < y1) << 1) | ((t2.vertex3.point.y < y1) << 2), y1);
+ for (auto t3 : tris3)
+ _crop_y(tris_final, t3, (t3.vertex1.point.y > y2) | ((t3.vertex2.point.y > y2) << 1) | ((t3.vertex3.point.y > y2) << 2), y2);
+ }
+ }
+ return tris_final;
+}
+#undef P1_OUT
+#undef P2_OUT
+#undef P3_OUT
+
+TriangleVertex4::TriangleVertex4(Vertex4 vertex1, Vertex4 vertex2, Vertex4 vertex3) : vertex1{vertex1}, vertex2{vertex2}, vertex3{vertex3} {
+}
+
+TriangleVertex4::TriangleVertex4(TriangleVertex3 triangle) : vertex1{triangle.vertex1}, vertex2{triangle.vertex2}, vertex3{triangle.vertex3} {
+}
+
+#define P1_OUT 1
+#define P2_OUT 2
+#define P3_OUT 4
+static void _crop_z(std::vector<TriangleVertex4>& tris, TriangleVertex4 t, int n, float z) {
+ switch (n) {
+ case 0:
+ tris.push_back(t);
+ break;
+ case P1_OUT:
+ case P2_OUT:
+ case P3_OUT:
+ case P2_OUT | P3_OUT:
+ case P1_OUT | P3_OUT:
+ case P1_OUT | P2_OUT:
+ {
+ Vertex4* q1;
+ Vertex4* q2;
+ Vertex4* q3;
+ switch (n) {
+ case P1_OUT:
+ case P2_OUT | P3_OUT:
+ q1 = &t.vertex1;
+ q2 = &t.vertex2;
+ q3 = &t.vertex3;
+ break;
+ case P2_OUT:
+ case P1_OUT | P3_OUT:
+ q1 = &t.vertex2;
+ q2 = &t.vertex1;
+ q3 = &t.vertex3;
+ break;
+ case P3_OUT:
+ case P1_OUT | P2_OUT:
+ q1 = &t.vertex3;
+ q2 = &t.vertex2;
+ q3 = &t.vertex1;
+ break;
+ }
+ MathVector4 dq2 = q1->point - q2->point;
+ float fac2 = (z - q2->point.z) / dq2.z;
+ Vertex4 r2{
+ {
+ q2->point.x + fac2 * dq2.x,
+ q2->point.y + fac2 * dq2.y,
+ z,
+ q2->point.w + fac2 * dq2.w
+ },
+ VertexData::lerp(q2->data, q1->data, fac2)
+ };
+ MathVector4 dq3 = q1->point - q3->point;
+ float fac3 = (z - q3->point.z) / dq3.z;
+ Vertex4 r3{
+ {
+ q3->point.x + fac3 * dq3.x,
+ q3->point.y + fac3 * dq3.y,
+ z,
+ q3->point.w + fac3 * dq3.w
+ },
+ VertexData::lerp(q3->data, q1->data, fac3)
+ };
+ switch (n) {
+ case P1_OUT:
+ tris.push_back({r3, *q2, *q3});
+ tris.push_back({r3, r2, *q2});
+ break;
+ case P2_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P3_OUT:
+ tris.push_back({r2, *q3, *q2});
+ tris.push_back({r2, r3, *q3});
+ break;
+ case P2_OUT | P3_OUT:
+ tris.push_back({*q1, r2, r3});
+ break;
+ case P1_OUT | P3_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ case P1_OUT | P2_OUT:
+ tris.push_back({*q1, r3, r2});
+ break;
+ }
+ }
+ break;
+ case P1_OUT | P2_OUT | P3_OUT:
+ break;
+ }
+}
+
+std::vector<TriangleVertex4> TriangleVertex4::crop_z_out(float z1, float z2) const {
+ std::vector<TriangleVertex4> tris;
+ _crop_z(tris, *this, (vertex1.point.z < z1) | ((vertex2.point.z < z1) << 1) | ((vertex3.point.z < z1) << 2), z1);
+ std::vector<TriangleVertex4> tris2;
+ for (auto t : tris)
+ _crop_z(tris2, t, (t.vertex1.point.z > z2) | ((t.vertex2.point.z > z2) << 1) | ((t.vertex3.point.z > z2) << 2), z2);
+ return tris2;
+}
+#undef P1_OUT
+#undef P2_OUT
+#undef P3_OUT
+
+TriangleVertex3 TriangleVertex4::div_by_w() const {
+ return {vertex1.div_by_w(), vertex2.div_by_w(), vertex3.div_by_w()};
+}
diff --git a/src/tri_vertex.h b/src/tri_vertex.h
new file mode 100644
index 0000000..5bbdd40
--- /dev/null
+++ b/src/tri_vertex.h
@@ -0,0 +1,29 @@
+#ifndef TRI_VERTEX_H
+#define TRI_VERTEX_H
+
+#include "vertex.h"
+#include <vector>
+
+class TriangleVertex3 {
+ public:
+ Vertex3 vertex1;
+ Vertex3 vertex2;
+ Vertex3 vertex3;
+
+ TriangleVertex3(Vertex3 vertex1, Vertex3 vertex2, Vertex3 vertex3);
+ std::vector<TriangleVertex3> crop_xy_out(float x1, float x2, float y1, float y2) const;
+};
+
+class TriangleVertex4 {
+ public:
+ Vertex4 vertex1;
+ Vertex4 vertex2;
+ Vertex4 vertex3;
+
+ TriangleVertex4(Vertex4 vertex1, Vertex4 vertex2, Vertex4 vertex3);
+ TriangleVertex4(TriangleVertex3 triangle);
+ std::vector<TriangleVertex4> crop_z_out(float z1, float z2) const;
+ TriangleVertex3 div_by_w() const;
+};
+
+#endif // TRI_VERTEX_H
diff --git a/src/vertex.cpp b/src/vertex.cpp
new file mode 100644
index 0000000..d136754
--- /dev/null
+++ b/src/vertex.cpp
@@ -0,0 +1,16 @@
+#include "vertex.h"
+#include "math_vector.h"
+#include "vertex_data.h"
+
+Vertex3::Vertex3(MathVector3 point, VertexData data) : point{point}, data{data} {
+}
+
+Vertex4::Vertex4(MathVector4 point, VertexData data) : point{point}, data{data} {
+}
+
+Vertex4::Vertex4(Vertex3 vertex) : point{vertex.point}, data{vertex.data} {
+}
+
+Vertex3 Vertex4::div_by_w() const {
+ return {point.div_by_w(), data};
+}
diff --git a/src/vertex.h b/src/vertex.h
new file mode 100644
index 0000000..92b7dcb
--- /dev/null
+++ b/src/vertex.h
@@ -0,0 +1,25 @@
+#ifndef VERTEX_H
+#define VERTEX_H
+
+#include "math_vector.h"
+#include "vertex_data.h"
+
+class Vertex3 {
+ public:
+ MathVector3 point;
+ VertexData data;
+
+ Vertex3(MathVector3 point, VertexData data);
+};
+
+class Vertex4 {
+ public:
+ MathVector4 point;
+ VertexData data;
+
+ Vertex4(MathVector4 point, VertexData data);
+ Vertex4(Vertex3 vertex);
+ Vertex3 div_by_w() const;
+};
+
+#endif // VERTEX_H
diff --git a/src/vertex_data.cpp b/src/vertex_data.cpp
new file mode 100644
index 0000000..23c8b03
--- /dev/null
+++ b/src/vertex_data.cpp
@@ -0,0 +1,12 @@
+#include "vertex_data.h"
+
+VertexData VertexData::lerp(VertexData& vd1, VertexData& vd2, float s) {
+ return {};
+}
+
+VertexData VertexData::bilerp(VertexData& vd1, VertexData& vd2, VertexData& vd3, float s, float t) {
+ return {};
+}
+
+VertexData::VertexData() {
+}
diff --git a/src/vertex_data.h b/src/vertex_data.h
new file mode 100644
index 0000000..e35d65a
--- /dev/null
+++ b/src/vertex_data.h
@@ -0,0 +1,12 @@
+#ifndef VERTEX_DATA_H
+#define VERTEX_DATA_H
+
+class VertexData {
+ public:
+ static VertexData lerp(VertexData& vd1, VertexData& vd2, float s);
+ static VertexData bilerp(VertexData& vd1, VertexData& vd2, VertexData& vd3, float s, float t);
+
+ VertexData();
+};
+
+#endif // VERTEX_DATA_H